LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

Linux v4l2子系统(1):RK3588 VI概述

本文从硬件框架、软件框架、Buildroot配置、相关源码、创建Video设备及其关系图,来对整个RK3588 VI有所了解。

基于对硬件架构的了解,然后通过

  1. Linux v4l2子系统(2):v4l2框架分析》。
  2. Linux v4l2子系统(3):video buffer》。
  3. Linux Media子系统:Media Controller设备》。

对v4l2和Media有个基本的了解,然后分解介绍不同硬件的驱动:

  1. Linux v4l2子系统(4):I2C&OV13850》。
  2. Linux v4l2子系统(5):MIPI DPHY》。
  3. Linux v4l2子系统(6):MIPI CSI2》。
  4. Linux v4l2子系统(7):CIF(VICAP)》。
  5. Linux v4l2子系统(8):Rockchip ISP》。

最后介绍v4l2的库文件以及相关应用:

  1. Linux v4l2子系统(9):libv4l2》。
  2. Linux v4l2子系统(10):基于opencv的v4l2应用》。
  3. camera:一个基于QT+Weston的Camera应用》。

1 RK3588 VI硬件框架

RK3588的VI(Video Input)硬件框架包括如下部分:

  • 外部MIPI/LVDS/DVP Camera采集数据,最对支持7路输入(6 MIPI + 1 DVP)。
  • MIPI接口:
    • CSI-2是MIPI针对摄像头芯片接口协议。
    • D/C-PHY同时支持D-PHY和C-PHY。
    • D-PHY支持1路4Lane,或者2路2Lane组合。
  • DVP接口或称为Camera并口,一般支持BT601/BT656/BT1120数据的传输。
  • VICAP负责将从MIPI获取的数据搬运到DDR。
  • ISP对Camera Sensor输出的图像信号进行后处理,最多支持4路数据源输入。VICAP数据到ISP支持直通和回读两种模式:
    • 直通:指数据经过VICAP采集,直接发送给ISP处理,不存储到DDR。需要注意的是hdr直通时,只有短帧是真正的直通,长帧需要存在DDR,ISP再从DDR读取。
    • 回读:指数据经过VICAP采集到DDR,应用获取到数据后,将buffer地址推送给ISP,ISP再从DDR获取图像数据。
  • FEC(Fish Eye Correction)负责鱼眼校正。

参考文档《Rockchip_Development_Guide_ISP30_CN_v1.2.3.pdf》。

2 RK3588 MIPI VI软件架构

如下是RK3588 VI链路框图:

  • DPHY0/1可以两种模式运行:
    • full mode:以节点csi2_dphy0/csi2_dphy3提供4 Lane MIPI接口。
    • split mode:以节点csi2_dphy1/csi2_dphy2/csi2_dphy4/csi2_dphy5提供2 Lane MIPI接口。
  • VICAP支持同时输入6路MIPI及1路DVP数据输入。
  • ISP支持同时4路输入,虚拟出4个设备节点。

以OV13850为例,详细解释数据链路:

  • OV13850由IC接口进行配置,需要MIPI 4 Lane将数据送到MIPI DPHY。
  • DPHY0 csi2_dphy0作为输入端,将数据送到CSI HOST2。
  • VICAP虚拟出多个设备,通过rkcif_mipi_lvds2设备接收数据,通过rkcif_mipi_lvds2_sditf输出到ISP0。
  • ISOP0虚拟出4个设备,通过rkisp0_vir0接收数据进行处理。

以OV13850为例,整个软硬件框架分为:

  • 硬件层:包含I2C Master、OV13850、DPHY、CSI2、VICAP、ISP等。
  • 内核驱动层:I2C Master Driver、OV13850 Driver、DPHY Driver、CSI2 Host Driver、RKCIF Driver、ISP Driver、v4l2 Subsystem、I2C Subsystem、Media Subsystem等。
  • 用户层:基于/dev/videoX设备的用户程序以及测试程序等。

3 RK3588 MIPI Camera配置

 RK3588 MIPI Camera以OV13850为例,配置如下:

  • 使能Media Support,以及v4l2。
  • 打开OV13850 Camera。
  • 打开RK I2C功能。
Device Drivers
  Multimedia support
    Media core support
      Video4Linux core
      Media Controller API
    Video4Linux options
      V4L2 sub-device userspace API
    Media ancillary drivers
      Camera sensor devices
        OmniVision OV13850 sensor support

4 RK3588 MIPI Camera文件

Camera通过I2C接口配置:

drivers/i2c/
├── algos
│   ├── i2c-algo-bit.c
├── busses
│   ├── i2c-rk3x.c
├── i2c-boardinfo.c
├── i2c-core-base.c
├── i2c-core-of.c
├── i2c-core-smbus.c
├── i2c-dev.c
├── i2c-mux.c

 v4l2 Core以及Camera文件:

drivers/media/
├── cec
│   ├── core
│   │   ├── cec-adap.c
│   │   ├── cec-api.c
│   │   ├── cec-core.c
│   │   ├── cec-notifier.c
├── common
│   └── videobuf2--v4l2内存管理。
│       ├── vb2-trace.c
│       ├── videobuf2-cma-sg.c
│       ├── videobuf2-core.c
│       ├── videobuf2-dma-contig.c
│       ├── videobuf2-dma-sg.c
│       ├── videobuf2-dvb.c
│       ├── videobuf2-memops.c
│       ├── videobuf2-v4l2.c
│       ├── videobuf2-vmalloc.c
├── i2c
│   ├── ov13850.c--OV13850驱动。
├── mc
│   ├── mc-dev-allocator.c
│   ├── mc-device.c
│   ├── mc-devnode.c
│   ├── mc-entity.c
│   ├── mc-request.c
├── platform
│   ├── rockchip
│   │   ├── cif--RKCIF驱动。
│   │   │   ├── capture.c
│   │   │   ├── cif-luma.c
│   │   │   ├── cif-scale.c
│   │   │   ├── cif-tools.c
│   │   │   ├── common.c
│   │   │   ├── dev.c
│   │   │   ├── hw.c
│   │   │   ├── mipi-csi2.c--RK3588 CSI2 Host驱动。
│   │   │   ├── procfs.c
│   │   │   ├── subdev-itf.c
│   │   ├── isp--RKISP驱动。
│   │   │   ├── bridge.c
│   │   │   ├── bridge_v30.c
│   │   │   ├── capture.c
│   │   │   ├── capture_v1x.c
│   │   │   ├── capture_v21.c
│   │   │   ├── capture_v30.c
│   │   │   ├── common.c
│   │   │   ├── csi.c
│   │   │   ├── dev.c
│   │   │   ├── dmarx.c
│   │   │   ├── hw.c
│   │   │   ├── isp_dvbm.c
│   │   │   ├── isp_params.c
│   │   │   ├── isp_params_v1x.c
│   │   │   ├── isp_params_v21.c
│   │   │   ├── isp_params_v32.c
│   │   │   ├── isp_params_v3x.c
│   │   │   ├── isp_rockit.c
│   │   │   ├── isp_stats.c
│   │   │   ├── isp_stats_v1x.c
│   │   │   ├── isp_stats_v21.c
│   │   │   ├── isp_stats_v2x.c
│   │   │   ├── isp_stats_v2x.h
│   │   │   ├── isp_stats_v32.c
│   │   │   ├── isp_stats_v32.h
│   │   │   ├── isp_stats_v3x.c
│   │   │   ├── procfs.c
│   │   │   ├── regs.c
│   │   │   ├── rkisp.c
│   │   └── rga
│   │       ├── rga-buf.c
│   │       ├── rga.c
│   │       ├── rga-hw.c
└── v4l2-core--v4l2核心。
    ├── tuner-core.c
    ├── v4l2-async.c
    ├── v4l2-clk.c
    ├── v4l2-common.c
    ├── v4l2-compat-ioctl32.c
    ├── v4l2-ctrls.c
    ├── v4l2-dev.c
    ├── v4l2-device.c
    ├── v4l2-dv-timings.c
    ├── v4l2-event.c
    ├── v4l2-fh.c
    ├── v4l2-flash-led-class.c
    ├── v4l2-fwnode.c
    ├── v4l2-h264.c
    ├── v4l2-i2c.c
    ├── v4l2-ioctl.c
    ├── v4l2-mc.c
    ├── v4l2-mem2mem.c
    ├── v4l2-spi.c
    ├── v4l2-subdev.c
    ├── v4l2-trace.c

 使用到的MIPI DPHY驱动:

drivers/phy/rockchip/
├── phy-rockchip-csi2-dphy.c--注册DPHY v4l2设备驱动。 ├── phy-rockchip-csi2-dphy-hw.c--获取DPHY硬件参数驱动。 

5 用户空间设备节点

v4l2设备:

v4l-subdev0 -> ../../devices/platform/fdd30000.mipi2-csi2/video4linux/v4l-subdev0
    rockchip-mipi-csi2
v4l-subdev1 -> ../../devices/platform/csi2-dphy0/video4linux/v4l-subdev1
    rockchip-csi2-dphy0
v4l-subdev2 -> ../../devices/platform/feab0000.i2c/i2c-3/3-0010/video4linux/v4l-subdev2
    m02_b_ov13850 3-0010
v4l-subdev3 -> ../../devices/platform/rkisp0-vir0/video4linux/v4l-subdev3
    rkisp-isp-subdev
v4l-subdev4 -> ../../devices/platform/rkcif-mipi-lvds2-sditf/video4linux/v4l-subdev4
    rkcif-mipi-lvds2

video0 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video0
    stream_cif_mipi_id0
video1 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video1
    stream_cif_mipi_id1
video2 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video2
    stream_cif_mipi_id2
video3 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video3
    stream_cif_mipi_id3

video4 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video4
    rkcif_scale_ch0
video5 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video5
    rkcif_scale_ch1
video6 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video6
    rkcif_scale_ch2
video7 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video7
    rkcif_scale_ch3

video8 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video8
    rkcif_tools_id0
video9 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video9
    rkcif_tools_id1
video10 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video10
    rkcif_tools_id2

video11 -> ../../devices/platform/rkisp0-vir0/video4linux/video11
    rkisp_mainpath
video12 -> ../../devices/platform/rkisp0-vir0/video4linux/video12
    rkisp_selfpath
video13 -> ../../devices/platform/rkisp0-vir0/video4linux/video13
    rkisp_fbcpath
video14 -> ../../devices/platform/rkisp0-vir0/video4linux/video14
    rkisp_iqtool

video15 -> ../../devices/platform/rkisp0-vir0/video4linux/video15
    rkisp_rawrd0_m
video16 -> ../../devices/platform/rkisp0-vir0/video4linux/video16
    rkisp_rawrd2_s
video17 -> ../../devices/platform/rkisp0-vir0/video4linux/video17
    rkisp_rawrd1_l

video18 -> ../../devices/platform/rkisp0-vir0/video4linux/video18
    rkisp-statistics
video19 -> ../../devices/platform/rkisp0-vir0/video4linux/video19
    rkisp-input-params
video20 -> ../../devices/platform/fdee0000.hdmirx-controller/video4linux/video20
    stream_hdmirx

5.1 通过media_gobj_create函数创建Media Graph

根据media_gobj_create()输出的log,使用如下脚本生成dot文件:

import re

dmesg_name = "rk3588-v4l2-boot.txt"
#interested_device_name = "rkcif-mipi-lvds2"
interested_device_name = "rkisp0-vir0"

entity_dict = {}
media_graph = {}
if __name__ == '__main__':
    print("strict digraph \"%s\" {"%(interested_device_name))
    print("\trankdir=LR")
    print("\tnodesep=1")
    print("\tranksep=1")
    with open(dmesg_name, 'r') as dmesg:
        for line in dmesg:
            if "media_gobj_create" in line:
                #[    5.170297] rkisp rkisp0-vir0: media_gobj_create id 1: entity 'rkisp-isp-subdev'
                #print(line)
                #m = re.match('\[ *(?P<time>.*)\] (?P<module>.*) (?P<device>.*): media_gobj_create id (?P<id>.[0-9]): (?P<t>.*)', line)
                #m = re.match('\[ *(?P<time>.*)\] (?P<module>[a-zA-Z0-9]*) (?P<device>.*): media_gobj_create id (?P<else>.*)', line)
                m = re.match('\[ *(?P<time>.*)\] (?P<module>[a-zA-Z0-9]*) (?P<device>.*): media_gobj_create id (?P<id>[0-9]*): (?P<else>.*)',line)
                if(m):
                    #device, id, t = m.group('device', 'id', 't')
                    #print("Device=%s, ID=%s, String=%s"%(device, id, t))
                    module_name = m.group("module")
                    device_name = m.group("device")
                    if device_name != interested_device_name:
                        continue
                    id_num = m.group("id")
                    media_graph_item = m.group("else")
                    #print("%s %s %s: %s"%(module_name, device_name, id_num, media_graph_item))
                    if "entity" in media_graph_item:
                        m = re.match("entity \'(?P<entity>.*)\'", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            print("\t%s[label=\"%s\", shape=box, fontcolor=Red, group=g%s];"%(id_num, entity_name, id_num))
                            entity_dict[entity_name]={"entity":id_num, "sink":[], "source":[]}
                        else:
                            print("Error in Entity: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "intf_devnode" in media_graph_item:
                        m = re.match("intf_devnode (?P<video>.*) - major: (?P<major>[0-9]*), minor: (?P<minor>[0-9]*)", media_graph_item)
                        if(m):
                            video_name = m.group("video")
                            major_name = m.group("major")
                            minor_name = m.group("minor")
                            if video_name == "v4l-video":
                                print("\t%s[label=\"IntfDevnode:%s%s\", fontcolor=Blue];"%(id_num, "/dev/video", minor_name))
                            elif video_name == "v4l-subdev":
                                print("\t%s[label=\"IntfDevnode:%s%s\", fontcolor=Blue];"%(id_num, "/dev/v4l-subdev", minor_name))
                            else:
                                sys.exit(1)
                        else:
                            print("Error in IntfDevnode: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "sink pad" in media_graph_item:
                        m = re.match("sink pad \'(?P<entity>.*)\':(?P<id>[0-9]*)", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            sink_id = m.group("id")
                            print("\t%s[label=\"SinkPad:%s-%s\", shape=cds, group=g%s];"%(id_num, entity_name, sink_id, entity_dict[entity_name]["entity"]))
                            print("\t%s->%s;"%(id_num, entity_dict[entity_name]["entity"]))
                            entity_dict[entity_name]["sink"].append(id_num)
                        else:
                            print("Error in SinkPad: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "source pad" in media_graph_item:
                        m = re.match("source pad \'(?P<entity>.*)\':(?P<id>[0-9]*)", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            sink_id = m.group("id")
                            print("\t%s[label=\"SourcePad:%s-%s\", shape=cds, group=g%s];"%(id_num, entity_name, sink_id, entity_dict[entity_name]["entity"]))
                            print("\t%s->%s;"%(entity_dict[entity_name]["entity"], id_num))
                            entity_dict[entity_name]["source"].append(id_num)
                        else:
                            print("Error in SourcePad: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "interface link" in media_graph_item:
                        m = re.match("interface link id (?P<src>[0-9]*) ==> id (?P<dst>[0-9]*)", media_graph_item)
                        if(m):
                            src_id=m.group("src")
                            dst_id=m.group("dst")
                            print("\t%s->%s;"%(src_id, dst_id))
                        else:
                            print("Error in InterfaceLink: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "data link" in media_graph_item:
                        m = re.match("data link id (?P<src>[0-9]*) ==> id (?P<dst>[0-9]*)", media_graph_item)
                        if (m):
                            src_id = m.group("src")
                            dst_id = m.group("dst")
                            print("\t%s->%s;" % (src_id, dst_id))
                        else:
                            print("Error in DataLink: %s"%(media_graph_item))
                            sys.exit(1)
                    else:
                        print("Error in: "%(media_graph_item))
                        sys.exit(1)
                else:
                    sys.exit(1)
                    print("Error:", line)
    print("}")
View Code

得到的Media Graph如下:

5.2 通过media-ctl生成dot创建Media Graph图

后来发现media-ctl生成更好的Media Graph图:

  • Entity用绿色框表示,输入Port为Entity Sink,输出Port为Entity Source。
  • 虚线表示可能的链路,实线表示当前激活链路。
  • IntfDevnode用黄色框表示。

通过如下命令生成dot,然后转成png:

media-ctl --d /dev/media0 --print-dot
dot -Tpng media0.dot  -o media0.png

 

 

参考资料:

V4L2框架概述》、《V4L2框架-media device》、《V4L2框架-v4l2 device》、《V4L2框架-control_v4l2_control》、《V4L2框架-control的数据结构》、《V4L2框架-videobuf2》。

RK3588-Camera:MIPI-CSI调试之通路解析》、《camera调试:RK3588 MIPI/DVP camera关键配置》。

RK3588s imx415相机适配及ISP调优系列(一)_rk_evb_imx415连接器》、《RK3588s imx415相机适配及ISP调优系列(二)--- mipi相机适配_rk3588 imx415》、《RK3588s imx415相机适配及ISP调优系列(三)--- RKISP调试环境配置》。

posted on 2024-04-06 23:59  ArnoldLu  阅读(2885)  评论(0编辑  收藏  举报

导航