高通Camera 驱动调试要点

Posted bobuddy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高通Camera 驱动调试要点相关的知识,希望对你有一定的参考价值。

 这篇文章主要介绍数据流这边Camera ISP这块所遇到的问题,主要介绍bus overflow和sof freeze;

(一)bus overflow


  摄像头传感器时钟通道(即 MIPI DDR 时钟)的工作频率与激活的数据通道数决定摄像头传感器在指定操作模式下的总数据传输速率(吞吐量)。每个通道的数据传输速率是 MIPI DDR 时钟速度的两倍。例如,工作在 200 MHz MIPI DDR 时钟频率和 4 个激活通道下的摄像头传感器的总数据传输速率为 1600 Mbps(每个通道的数据传输速率为 200 * 2 = 400 Mbps)。

  每个帧的分辨率、额外/虚拟像素/线数、水平消隐、垂直消隐、MIPI 包开销、每像素位数、数据格式、内部是否存在多个交错数据流以及每个流的数据传输速率/开销等,都会影响数据传输速率。指定工作模式下初步摄像头调通,计算:X = 帧宽 * (帧高垂直消隐) 每像素位数 * 每秒帧数 * (MIPI 协议和其他数据流的开销)在 VFE 时钟优化中为给定的 MSM 找到大于 X 的最接近的值作为 VFE 时钟的初始值。

  在标称时钟模式下,比如MSM8909的VFE最大速度为266MHz每条MIPI通道的PHY限制为1.5 Gbps (1.5 * 109 bps),由于存在MIPI/空白开销(约15-25%,各传感器的具体数值有所不同),实际帧数据吞吐量略少于预期原图拍摄接口数据传输速率与VFE时钟无关在4通道PHY接口上,每条通道的最大数据为(266 x bpp)/通道数;bpp → 每像素的传感器输出位数对于每通道10位数据传输速率 - (266*10)/4 - 665 Mbps;

  当我们VFE 时钟设置为小于传感器输出MIPI的数据传输速率时,将出现溢出bus overflow;

502:        pr_err_ratelimited("%s: image master 0 bus overflow\\n",
507:        pr_err_ratelimited("%s: image master 1 bus overflow\\n",
512:        pr_err_ratelimited("%s: image master 2 bus overflow\\n",
517:        pr_err_ratelimited("%s: image master 3 bus overflow\\n",
522:        pr_err_ratelimited("%s: image master 4 bus overflow\\n",
527:        pr_err_ratelimited("%s: image master 5 bus overflow\\n",
532:        pr_err_ratelimited("%s: image master 6 bus overflow\\n",

  增大VFE时钟可防止溢出发生。要更改VFE时钟,需打Vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/sensor_libs/xxxx/ xxxx_lib.c文并编辑 op_pixel_clk 参数。

  选择正确的 VFE 时钟非常重要。VFE 时钟频率应足够高以匹配传感器输出端的数据速率(即传感器输出帧 x 帧/s),否则可能会引起 ISPIF 溢出。不过也不应设置过高的频率。设置过高的 VFE 时钟频率会导致两类问题:
1. 由于可能填充内部 VFE 输出缓存(也称为统一缓存),总线溢出的几率增大。
2. 如果 VFE 时钟频率较高,会导致功耗增大。


A. 检查与 VFE 总线溢出相关的总线时钟

  当过多的 VFE 数据流量以超过可用总线带宽的速率产生时,会导致 VFE 总线溢出错误。解决该问题的一种可行方法是检查能否通过设置更高的总线时钟频率来增加总线带宽。例如在 MSM8916 芯片组中,VFE 生成处理后的输出帧到系统 NoC (SNoC) 总线。数据流随后被转发到总线集成内存控制器 (BIMC) 总线,暂时保存在 DDR 内存中。VFE 生成的数据流将在这两条总线形成的路径上运行。因此,SNoC 和 BMIC 总线都必须进行检查。adb shell 脚本每隔一秒会转储 SNoC 和 BIMC 时钟频率。

#adb shell "while true; do cat /d/clk/snoc_clk/measure; cat /d/clk/bimc_clk/measure; echo '-----'; sleep 1; done"

200001391
748805675
-----
 

B. 将时钟总线设为最大频率

  VFE 总线溢出分类的第一步是检查能否通过设置更高总线时钟频率来增加可用总线带宽。增加总线带宽后,查看 VFE 总线溢出问题是否得以解决。

adb root
adb shell sleep 1
adb shell mount -t debugfs none /d
adb shell echo "22 > /d/msm-bus-dbg/shell-client/mas"
adb shell echo "512 > /d/msm-bus-dbg/shell-client/slv"
adb shell echo "0 > /d/msm-bus-dbg/shell-client/ab"
adb shell echo "6400000000 > /d/msm-bus-dbg/shell-client/ib"
adb shell echo "1 > /d/msm-bus-dbg/shell-client/update_request"

  以上脚本尝试设置从 MDP(显示硬件模块)到 DDR 内存路径中的所有总线。不管摄像头如何操作,通过从 MDP 显示屏侧(ID 22 表示 MDP)请求高带宽,总线会始终保持最大时钟频率。选择显示屏 (MDP) 而不是摄像头 ISP (VFE) 的原因是显示屏 MDP 一直运行,而摄像头驱动程序在启动和停止时会覆盖摄像头表决。而且这种更简单的测试场景能解决所有起伏问题。通过以上测试,再次检查总线时钟是否增加到最大频率。应用上述设置后,SNoC 和BIMC 时钟频率分别应为 266 MHz 和 533 MHz(不同平台参数不一致,对应不同的性能等级)。

  如果没有任何改进,可尝试按以下步骤在 CPU 高性能模式下运行系统并设置最大总线时钟频率:

adb shell "echo 1 > /sys/devices/system/cpu/cpu1/online"

adb shell "echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
 

C. 从 VFE 检查 AB/IB 表决带宽


在检查 VFE 侧要求的总 AB 和 IB 带宽时,确保摄像头已启动
运行以下命令:
adb root
adb shell cat /d/msm-bus-dbg/client-data/msm_camera_isp

1223.023734896
curr   : 1
masters: 29  
slaves : 512  
ab     : 100000000  
ib     : 100000000  

1223.024648282
curr   : 2
masters: 29  
slaves : 512  
ab     : 200000000  
ib     : 200000000  

1228.214552238
curr   : 1
masters: 29  
slaves : 512  
ab     : 921819520  
ib     : 921819520 


  输出第一行中的数字 351.706326427 表示发出请求时的内核时间戳。Master(s) 29 表示总线流量来自 VFE,Slave(s) 512 表示总线流量的目的地设为 memory;AB/IB VFE 发出的最终宽带请求分别为 930 MBps/1.62 GBps。


D. 识别 AXI 配置


  VFE 总线溢出日志经常始于表明某个具体写入主控上出现溢出,因此内核日志显示的首个溢出实例就显得非常重要,可以帮助确认溢出来源。在 VFE 总线溢出分析(特别是 ZSL 预览场景)过程中,通常要求找到具体图像写入主器件和预览/快照输出帧面的映射关系,以确定要优化的数据流。例如,确定预览数据流的总线溢出后,仅关注预览数据流。在内核中添加以下调试日志消息,并在 Salesforce 用列系统分享该日志。

--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1384,8 +1384,10 @@ static int  msm_isp_axi_stream_enable_cfg(
        if (stream_info->state == START_PENDING ||
                stream_info->state == RESUME_PENDING)
                enable_wm = 1;
+        pr_err("__debug__: WM[%d] ENABLE, src = %d, max_width = %u\\n",stream_info->wm[i], stream_info->stream_src, stream_info->max_width);
        else
                enable_wm = 0;
+        pr_err("__debug__: WM[%d] DISENABLE, src = %d, max_width = %u\\n",stream_info->wm[i], stream_info->stream_src, stream_info->max_width);
       
 

E. 增加 AB/IB


  如果将时钟总线设为最大频率,能够解决buffer ovflow的问题,可以尝试增加总体总线时钟频率,总线时钟频率只会在摄像头工作时增加,逐渐增加或将原来数字乘2或逐渐减少来找出最优数量。

//kernel/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c

 62 #define MSM_ISP_MIN_AB 100000000                                                                                                                   
 63 #define MSM_ISP_MIN_IB 100000000
 

F. 提高VFE 突发长度变化


  尽管最优 VFE 突发长度没有明确答案,但改变 VFE 突发长度也能够减少 VFE 总线溢出问题。

  28 #define VFE40_BURST_LEN 1                                                                                                                         
  29 #define VFE40_BURST_LEN_8916_VERSION 2
  30 #define VFE40_BURST_LEN_8952_VERSION 3

  33 #define VFE40_STATS_BURST_LEN 1
  34 #define VFE40_STATS_BURST_LEN_8916_VERSION 2
 

(二)sof freeze


  sof freeze(SOF:start of frame)表示ISP这边没有收到sensor这边输出的图像帧数据,这时必须检查 CSID/CSIPHY/CAMIF是否出错。有专门建立了thread来负责SOF的检测,start_sof_check_thread() -> mct_bus_sof_thread_run(),log当中会有下面的错误发出:

// msm-3.18/drivers/media/platform/msm/camera_v2/msm.c

 803     case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG:
 804         if (event_data->status)
 805             pr_err("%s:Notifying subdevs about potential sof freeze\\n",
 806                 __func__);

  首先看能否dump出现数据:

        /*
        0 Disabled; this value is set by default
        2 Dump preview frames
        8 Dump snapshot frames
        16 Dump video frames
        */

        adb root
        adb shell setprop persist.camera.isp.dump 8
        adb shell chmod 777 /data

   Verifying the VFE hardware configuration

    In the msm_isp_axis_util.c file, locate the following code snippet:

    if (vfe_dev->dump_reg)
     msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);

    Replace it with:

    24 if (1)
    25 msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);

   若声明的传感器输出大小与 VFE 实际接收到的传感器输出大小之间不匹配,将发生 CAMIF错误。

//mm-camera/mm-camera2/media-controller/modules/iface2/iface_util.c

 8878 static void iface_util_dump_camif_cfg(struct msm_vfe_input_cfg *input_cfg)                                                                       
 8879
 8880   struct msm_vfe_pix_cfg *pix_cfg = NULL;
 8881 
 8882   if (input_cfg == NULL)
 8883     return;
 8884 
 8885   pix_cfg = &input_cfg->d.pix_cfg;
 8886   IFACE_HIGH("=====Camif DUMP cfg for PIX interface====\\n");
 8887   IFACE_HIGH("camif input type = %d(MIPI=3), op_pix_clk = %d\\n",
 8888     pix_cfg->camif_cfg.camif_input, input_cfg->input_pix_clk);
 8889   IFACE_HIGH("camif pix_pattern(RGRG-0/GRGR-1/BGBG-2/GBGB-3) = %d\\n",
 8890     pix_cfg->pixel_pattern);
 8891   IFACE_HIGH("camif first_pix = %d, last_pix = %d\\n",
 8892     pix_cfg->camif_cfg.first_pixel, pix_cfg->camif_cfg.last_pixel);
 8893   IFACE_HIGH("camif first_line = %d, last_line = %d\\n",
 8894     pix_cfg->camif_cfg.first_line, pix_cfg->camif_cfg.last_line);
 8895   IFACE_HIGH("camif pixels_per_line = %d, lines_per_frame = %d\\n",
 8896     pix_cfg->camif_cfg.pixels_per_line, pix_cfg->camif_cfg.lines_per_frame);
 8897   IFACE_HIGH("camif irq subsample pattern = %x, period = %d sof_step %d\\n",
 8898     pix_cfg->camif_cfg.subsample_cfg.irq_subsample_pattern,
 8899     pix_cfg->camif_cfg.subsample_cfg.irq_subsample_period,
 8900     pix_cfg->camif_cfg.subsample_cfg.sof_counter_step);
 8901


  将调试消息中指示的帧大小与 ISP 传感器的帧大小进行比较。在以下 CAMIF 错误示例中,错误状态 0x9a70a00 表示 ISP 接收帧的大小为 2471x2560(0x9a7 = 2471,0xa00 = 2560)。

01-01 08:07:20.175 E/mm-camera( 302): isp_hw_camif_dump_cfg: camif
input_format= 0 
01-01 08:07:20.175 E/mm-camera( 302): isp_hw_camif_dump_cfg: camif
last_pix = 6527 
01-01 08:07:20.175 E/mm-camera( 302): isp_hw_camif_dump_cfg: camif
last_line = 0 
01-01 08:07:20.175 E/mm-camera( 302): isp_hw_camif_dump_cfg: camif
lines per frame = 2448 
01-01 08:07:24.335 E/klogd (640): [81.563301]
msm_vfe40_process_error_status: camif error status: 0x9a70a00

如果存在不匹配,则根本原因可能如下:

  检查传感器设置是否正确,是否满足分辨率大小的要求。例如,传感器的输出大小配置为 12 MB,但 ISP 的接收大小却配置为 8 MB。可能有些传感器无法确保在新分辨率设置发送至传感器后,最初的帧大小能够满足要求。在这种情况下,需要与传感器供应商一起解决此问题。
 

以上是关于高通Camera 驱动调试要点的主要内容,如果未能解决你的问题,请参考以下文章

Android : 高通平台Camera调试

高通平台Camera调试

高通camera基本代码架构

高通平台开发系列讲解(摄像头篇)QCM6490 上摄像头驱动开发

高通平台开发系列讲解(Camera篇)新增GC8034摄像头步骤

【Camera专题】Camera驱动源码全解析_下