Camera | 6.v4l2拓扑架构

Camera | 6.v4l2拓扑架构一 设备节点 模块 拓扑结构关系拓扑结构是我们了解 MIPI CSI 内部模块以及与摄像头连接关系的最直观最便捷的方法 1 如何表示拓扑结构 file 视角 v4l2 视角来自 参考文档 RKISP Driver User Manual v1

欢迎大家来到IT世界,在知识的湖畔探索吧!

一、 设备节点、模块、拓扑结构关系

拓扑结构是我们了解MIPI-CSI内部模块以及与摄像头连接关系的最直观最便捷的方法。

1. 如何表示拓扑结构?

  • file视角
  • v4l2视角

来自: 参考文档《RKISP_Driver_User_Manual_v1.3.pdf》

  • 模块之间相互独立,通过struct media_entity来进行抽象,通常会将struct media_entity嵌入到其他结构中,以支持media framework功能;
  • entity模块包含struct media_pad,pad可以认为是端口,与其他模块进行联系的媒介,针对特定模块来说它是确定的;
  • pad通过struct media_link来建立连接,指定source和sink,即可将通路建立起来;
  • 各个模块之间最终建立一条数据流,便是一条pipeline了,同一条pipeline中的模块,可以根据前一个模块查找到下一个模块,因此也可以很方便进行遍历,并做进一步的设置操作;

2. 设备节点——-少media的

在/sys/class/video4linux/下可以找到v4l2相关的设备节点:

rk3568_r:/ # ls sys/class/video4linux ls sys/class/video4linux v4l-subdev0 v4l-subdev2 video1 video3 video5 video7 v4l-subdev1 video0 video2 video4 video6 video8 rk3568_r:/ # cat sys/class/video4linux/video0/dev cat sys/class/video4linux/video0/dev 81:0 rk3568_r:/ # cat sys/class/video4linux/video0/name cat sys/class/video4linux/video0/name rkisp_mainpath 

欢迎大家来到IT世界,在知识的湖畔探索吧!

udev文件系统会为我们在dev/目录下创建一个video0节点,即dev/video0

用户可以打开dev/video0节点,通过IOCTL命令和内核空间进行通信。

欢迎大家来到IT世界,在知识的湖畔探索吧!rk3568_r:/ # ls /dev/video* -l ls /dev/video* -l crw-rw---- 1 media camera 81, 0 2022-11-09 17:06 /dev/video0 crw-rw---- 1 media camera 81, 1 2022-11-09 17:06 /dev/video1 crw-rw---- 1 media camera 81, 2 2022-11-09 17:06 /dev/video2 crw-rw---- 1 media camera 81, 3 2022-11-09 17:06 /dev/video3 crw-rw---- 1 media camera 81, 4 2022-11-09 17:06 /dev/video4 crw-rw---- 1 media camera 81, 5 2022-11-09 17:06 /dev/video5 crw-rw---- 1 media camera 81, 6 2022-11-09 17:06 /dev/video6 crw-rw---- 1 media camera 81, 7 2022-11-09 17:06 /dev/video7 crw-rw---- 1 media camera 81, 8 2022-11-09 17:06 /dev/video8 rk3568_r:/ # ls /dev/v4l-sub* -l ls /dev/v4l-sub* -l crw-rw-rw- 1 media camera 81, 9 2022-11-09 17:06 /dev/v4l-subdev0 crw-rw-rw- 1 media camera 81, 10 2022-11-09 17:06 /dev/v4l-subdev1 crw-rw-rw- 1 media camera 81, 11 2022-11-09 17:06 /dev/v4l-subdev2 

3.拓扑结构图

命令media-ctl可以查看拓扑结构图

rk3568_r:/ # media-ctl -d /dev/media0 -p media-ctl -d /dev/media0 -p Opening media device /dev/media0 Enumerating entities Found 13 entities Enumerating pads and links Media controller API version 0.0.255 Media device information ------------------------ driver rkisp-vir0 model rkisp0 serial bus info hw revision 0x0 driver version 0.0.255 Device topology - entity 1: rkisp-isp-subdev (4 pads, 7 links) type V4L2 subdev subtype Unknown device node name /dev/v4l-subdev0 pad0: Sink [fmt:SBGGR10/4224x3136 crop.bounds:(0,0)/4096x3072 crop:(0,0)/4096x3072] <- "rkisp-csi-subdev":1 [] <- "rkisp_rawrd0_m":0 [] <- "rkisp_rawrd2_s":0 [] pad1: Sink <- "rkisp-input-params":0 [] pad2: Source [fmt:YUYV2X8/4096x3072 crop.bounds:(0,0)/4096x3072 crop:(0,0)/4096x3072] -> "rkisp_mainpath":0 [] -> "rkisp_selfpath":0 [] pad3: Source -> "rkisp-statistics":0 [] - entity 6: rkisp-csi-subdev (6 pads, 5 links) type V4L2 subdev subtype Unknown device node name /dev/v4l-subdev1 pad0: Sink <- "rockchip-csi2-dphy0":1 [] pad1: Source -> "rkisp-isp-subdev":0 [] pad2: Source -> "rkisp_rawwr0":0 [] pad3: Source pad4: Source -> "rkisp_rawwr2":0 [] pad5: Source -> "rkisp_rawwr3":0 [] - entity 13: rkisp_mainpath (1 pad, 1 link) type Node subtype V4L device node name /dev/video0 pad0: Sink <- "rkisp-isp-subdev":2 [] - entity 19: rkisp_selfpath (1 pad, 1 link) type Node subtype V4L device node name /dev/video1 pad0: Sink <- "rkisp-isp-subdev":2 [] - entity 25: rkisp_rawwr0 (1 pad, 1 link) type Node subtype V4L device node name /dev/video2 pad0: Sink <- "rkisp-csi-subdev":2 [] - entity 31: rkisp_rawwr2 (1 pad, 1 link) type Node subtype V4L device node name /dev/video3 pad0: Sink <- "rkisp-csi-subdev":4 [] - entity 37: rkisp_rawwr3 (1 pad, 1 link) type Node subtype V4L device node name /dev/video4 pad0: Sink <- "rkisp-csi-subdev":5 [] - entity 43: rkisp_rawrd0_m (1 pad, 1 link) type Node subtype V4L device node name /dev/video5 pad0: Source -> "rkisp-isp-subdev":0 [] - entity 49: rkisp_rawrd2_s (1 pad, 1 link) type Node subtype V4L device node name /dev/video6 pad0: Source -> "rkisp-isp-subdev":0 [] - entity 55: rkisp-statistics (1 pad, 1 link) type Node subtype V4L device node name /dev/video7 pad0: Sink <- "rkisp-isp-subdev":3 [] - entity 61: rkisp-input-params (1 pad, 1 link) type Node subtype V4L device node name /dev/video8 pad0: Source -> "rkisp-isp-subdev":1 [] - entity 67: rockchip-csi2-dphy0 (2 pads, 2 links) type V4L2 subdev subtype Unknown device node name /dev/v4l-subdev2 pad0: Sink <- "m00_b_ov13850 4-0010":0 [] pad1: Source -> "rkisp-csi-subdev":0 [] - entity 70: m00_b_ov13850 4-0010 (1 pad, 1 link) type V4L2 subdev subtype Sensor device node name /dev/v4l-subdev3 pad0: Source [fmt:SBGGR10/4224x3136] -> "rockchip-csi2-dphy0":0 [] 

下面是根据显示内容绘制的拓扑图:

Camera | 6.v4l2拓扑架构



欢迎大家来到IT世界,在知识的湖畔探索吧!

拓扑结构

该图中各个entity对应的设备节点名称已经标注。 模块的上方的黄色pad默认是source pad,下方的黄色pad是sink pad

字符设备类型主要有两种(只考虑摄像头):

  • /dev/videox (x取值0~8) (所有设备共用主设备号81,次设备号区分)
  • /dev/v4l-subdevx (x取值0~3)

video设备主要用于图像操作,必须创建结构体struct video_device变量, v4l-subdev设备主要对应sensor等具体从设备,必须创建struct v4l2_subdev变量, 内部的isp和csi、csi-dphy也都需要注册为subdev

这些entity由media_entity模块负责维护,将他们连接起来。

4. 模块功能

这些entity瑞芯微已经设定了他们各自的功能:

Camera | 6.v4l2拓扑架构

Camera | 6.v4l2拓扑架构

这些entity我们可以理解为一个个功能模块。

这些功能模块有的用于驱动csi、有的驱动isp、有的用于预览图像、有的用于统计视频信息、有的用于配置参数。

这些功能模块,并不是都一定每个camera控制器都有的,有一些是通用的,比如,mainpath、selfpath,有一些要完全看SoC设计,即使瑞芯微的SoC,不同型号,差别也不小。所以具体问题要具体分析,不可教条。

v4l2只定义了基本架构,定义好了回调函数接口,要实现模块具体功能只需要填充好对应的回调函数即可,应用层通过这些字符设备文件和对应的ioctrl命令,就可以实现相应的功能。

二、 如何描述拓扑?

1. struct rkisp_device

rk3568的camera控制器使用结构体struct rkisp_device管理所有的资源。

欢迎大家来到IT世界,在知识的湖畔探索吧!/* * struct rkisp_device - ISP platform device * @base_addr: base register address * @active_sensor: sensor in-use, set when streaming on * @isp_sdev: ISP sub-device * @cap_dev: image capture device * @stats_vdev: ISP statistics output device * @params_vdev: ISP input parameters device * @dmarx_dev: image input device * @csi_dev: mipi csi device * @br_dev: bridge of isp and ispp device */ struct rkisp_device { struct list_head list; void __iomem *base_addr; struct device *dev; char name[128]; void *sw_base_addr; struct rkisp_hw_dev *hw_dev; struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; struct media_device media_dev; struct v4l2_async_notifier notifier; struct v4l2_subdev *subdevs[RKISP_SD_MAX]; struct rkisp_sensor_info *active_sensor; struct rkisp_sensor_info sensors[RKISP_MAX_SENSOR]; int num_sensors; struct rkisp_isp_subdev isp_sdev; struct rkisp_capture_device cap_dev; struct rkisp_isp_stats_vdev stats_vdev; struct rkisp_isp_params_vdev params_vdev; struct rkisp_dmarx_device dmarx_dev; struct rkisp_csi_device csi_dev; struct rkisp_bridge_device br_dev; struct rkisp_luma_vdev luma_vdev; struct proc_dir_entry *procfs; struct rkisp_pipeline pipe; enum rkisp_isp_ver isp_ver; struct rkisp_emd_data emd_data_fifo[RKISP_EMDDATA_FIFO_MAX]; unsigned int emd_data_idx; unsigned int emd_vc; unsigned int emd_dt; int vs_irq; struct gpio_desc *vs_irq_gpio; struct rkisp_hdr hdr; unsigned int isp_state; unsigned int isp_err_cnt; unsigned int isp_isr_cnt; unsigned int isp_inp; struct mutex apilock; /* mutex to serialize the calls of stream */ struct mutex iqlock; /* mutex to serialize the calls of iq */ wait_queue_head_t sync_onoff; dma_addr_t resmem_addr; phys_addr_t resmem_pa; size_t resmem_size; int dev_id; unsigned int skip_frame; unsigned int irq_ends; unsigned int irq_ends_mask; bool send_fbcgain; struct rkisp_ispp_buf *cur_fbcgain; struct rkisp_buffer *cur_spbuf; bool is_thunderboot; struct kfifo rdbk_kfifo; spinlock_t rdbk_lock; int rdbk_cnt; int rdbk_cnt_x1; int rdbk_cnt_x2; int rdbk_cnt_x3; u32 rd_mode; u8 filt_state[RDBK_F_MAX]; }; 

其中与isp2.1拓扑结构相关的的几个结构体成员以及他们之间的关系:

成员 含义 拓扑图中的entity 设备名

Camera | 6.v4l2拓扑架构

2. 举例1:rkisp-csi-subdev注册到拓扑结构中

要添加到拓扑结构中,表示该模块的结构体中包含成员struct media_pad ,它和struct v4l2_subdev中的 struct media_entity entity;共同生成拓扑结构。

rkisp-csi-subdev设备结构体定义如下:

struct rkisp_csi_device { struct rkisp_device *ispdev; struct v4l2_subdev sd; struct media_pad pads[CSI_PAD_MAX]; struct sink_info sink[CSI_PAD_MAX - 1]; int max_pad; u32 err_cnt; u32 irq_cnt; u8 mipi_di[CSI_PAD_MAX - 1]; u8 tx_first[HDR_DMA_MAX]; }; 

参考第二节的拓扑图中 entity6 :

Camera | 6.v4l2拓扑架构

由上图可知,该模块有6个pad,pad属性定义如下

欢迎大家来到IT世界,在知识的湖畔探索吧!#define MEDIA_PAD_FL_SINK (1 << 0) #define MEDIA_PAD_FL_SOURCE (1 << 1) #define MEDIA_PAD_FL_MUST_CONNECT (1 << 2) 

pad的名称定义如下:

enum rkisp_csi_pad { CSI_SINK = 0, CSI_SRC_CH0, CSI_SRC_CH1, CSI_SRC_CH2, CSI_SRC_CH3, CSI_SRC_CH4, CSI_PAD_MAX }; 

isp的in pad

欢迎大家来到IT世界,在知识的湖畔探索吧!//isp的in pad enum rkisp_isp_inp { INP_INVAL = 0, INP_RAWRD0 = BIT(0), INP_RAWRD1 = BIT(1), INP_RAWRD2 = BIT(2), INP_CSI = BIT(4), INP_DVP = BIT(5), INP_DMARX_ISP = BIT(6), INP_LVDS = BIT(7), INP_CIF = BIT(8), }; 

根据该拓扑图,pads[0]sinkpads[1~5] 均为source

以下是驱动中pad初始化代码:

 rkisp_register_csi_subdev() { …… v4l2_subdev_init(sd, &rkisp_csi_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; //是否需要子节点 sd->entity.ops = &rkisp_csi_media_ops; sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; snprintf(sd->name, sizeof(sd->name), CSI_DEV_NAME);//名字前缀,#define CSI_DEV_NAME DRIVER_NAME "-csi-subdev" csi_dev->pads[CSI_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; //pad0属性 csi_dev->pads[CSI_SRC_CH0].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; //pad1属性 csi_dev->max_pad = CSI_SRC_CH0 + 1; if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) { csi_dev->max_pad = CSI_PAD_MAX; csi_dev->pads[CSI_SRC_CH1].flags = MEDIA_PAD_FL_SOURCE;//pad2属性 csi_dev->pads[CSI_SRC_CH2].flags = MEDIA_PAD_FL_SOURCE;//pad3属性 csi_dev->pads[CSI_SRC_CH3].flags = MEDIA_PAD_FL_SOURCE;//pad4属性 csi_dev->pads[CSI_SRC_CH4].flags = MEDIA_PAD_FL_SOURCE;//pad5属性 } ret = media_entity_pads_init(&sd->entity, csi_dev->max_pad, csi_dev->pads); …… } 

一些关键的宏汇总:

欢迎大家来到IT世界,在知识的湖畔探索吧!//各个模块对应的名字 【kernel\drivers\media\platform\rockchip\isp\dev.h】 #define DRIVER_NAME "rkisp" #define ISP_VDEV_NAME DRIVER_NAME "_ispdev" #define SP_VDEV_NAME DRIVER_NAME "_selfpath" #define MP_VDEV_NAME DRIVER_NAME "_mainpath" #define DMA_VDEV_NAME DRIVER_NAME "_dmapath" #define RAW_VDEV_NAME DRIVER_NAME "_rawpath" #define DMATX0_VDEV_NAME DRIVER_NAME "_rawwr0" #define DMATX1_VDEV_NAME DRIVER_NAME "_rawwr1" #define DMATX2_VDEV_NAME DRIVER_NAME "_rawwr2" #define DMATX3_VDEV_NAME DRIVER_NAME "_rawwr3" #define DMARX0_VDEV_NAME DRIVER_NAME "_rawrd0_m" #define DMARX1_VDEV_NAME DRIVER_NAME "_rawrd1_l" #define DMARX2_VDEV_NAME DRIVER_NAME "_rawrd2_s" #define GRP_ID_SENSOR BIT(0) #define GRP_ID_MIPIPHY BIT(1) #define GRP_ID_ISP BIT(2) #define GRP_ID_ISP_MP BIT(3) #define GRP_ID_ISP_SP BIT(4) #define GRP_ID_ISP_DMARX BIT(5) #define GRP_ID_ISP_BRIDGE BIT(6) #define GRP_ID_CSI BIT(7) //pad的属性 [kernel\include\uapi\linux\media.h] #define MEDIA_PAD_FL_SINK (1 << 0) #define MEDIA_PAD_FL_SOURCE (1 << 1) #define MEDIA_PAD_FL_MUST_CONNECT (1 << 2) 

由代码可得,拓扑关系由csi_dev->pads描述。

最终调用函数media_entity_pads_init()注册。

rkisp_register_platform_subdevs() isp_subdev_notifier() v4l2_async_notifier_parse_fwnode_endpoints() __v4l2_async_notifier_parse_fwnode_endpoints() { for ( fwnode = fwnode_graph_get_next_endpoint()) { dev_fwnode = fwnode_graph_get_port_parent(fwnode); is_available = fwnode_device_is_available(dev_fwnode); fwnode_handle_put(dev_fwnode); fwnode_graph_parse_endpoint(fwnode, &ep); } for ( fwnode = fwnode_graph_get_next_endpoint()) { dev_fwnode = fwnode_graph_get_port_parent(fwnode); is_available = fwnode_device_is_available(dev_fwnode); fwnode_handle_put(dev_fwnode); fwnode_graph_parse_endpoint(fwnode, &ep); v4l2_async_notifier_fwnode_parse_endpoint(); } fwnode_handle_put(fwnode); } 

大家也可以试着去分析其他的模块。

三、设备树如何描述摄像头拓扑结构?

1. 设备树说明文档

瑞芯微MIPI-CSI设备树节点属性说明参考内核说明文档:

欢迎大家来到IT世界,在知识的湖畔探索吧![kernel\Documentation\devicetree\bindings\media\] video-interfaces.txt 关于sensor节点属性的说明,接口类型, rockchip-isp1.txt isp模块属性说明 rockchip-mipi-dphy.txt dphy模块的说明 kernel\Documentation\devicetree\bindings\media\i2c\ovxxxxxx.txt ov系列的摄像设备树说明 

这些文档中有关于port、remote-endpoint等节点的详细说明,如果不是厂家,我们只需要搞懂摄像头拓扑结构即可。

2. ov13850

我们移植的摄像头为ov13850,他的连接关系如下:

  • 数据通道通过mipi接口连接到rk3568的mipi通道0
  • Camera控制器的csi2-dphy0模块负责从mipi通道中接收数据帧

外设摄像头拓扑关系由设备树来描述,内核会自动解析并帮我们自动注册。

千言万语,不如一图:

Camera | 6.v4l2拓扑架构

由上图可得:

  1. 摄像头ov13850设备树只有一个port子节点,所以pad为0,out表示该pad是source pad
  2. remote-endpoint属性表示该pad连接的上游模块的pad名字:mipi_in_ucam0,而模块csi2_dphy0中包含pad:mipi_in_ucam0,所以ov13850连接到该模块
  3. csi2_dphy0 port0节点的mipi_in_ucam0设备,通过remote-endpoint即可知道该pad所连接的是设备ov13850的pad
  4. 综上可得csi2_dphy0的pad0(sink pad)连接的ov13850的pad0(source pad)

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/103592.html

(0)
上一篇 2026年 1月 24日 上午7:10
下一篇 2026年 1月 24日 上午7:23

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信