Camera | 6.v4l2拓扑架构
创始人
2024-06-02 22:59:15
0

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

拓扑结构是我们了解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  video8rk3568_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

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

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

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/video8rk3568_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 []                                                              

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

拓扑结构

该图中各个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瑞芯微已经设定了他们各自的功能:


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

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

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

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

二、 如何描述拓扑?

1. struct rkisp_device

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

/** 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设备名
void __iomem *base_addr基地址--
struct rkisp_sensor_info *active_sensor;正在使用的sensor--
struct rkisp_isp_subdev isp_sdev;isp模块rkisp-isp-subdevv4l-subdev0
struct rkisp_capture_device cap_dev;capture模块, 维护struct vb2_v4l2_buffer对应拓扑图中的rkisp_mainpath、rkisp_selfpath、rkisp_rawwr0、rkisp_rawwr2、rkisp_rawwr3video0~video4
struct rkisp_isp_stats_vdev stats_vdev;数据统计模块rkisp-statisticsvideo7
struct rkisp_isp_params_vdev params_vdev;参数配置模块rkisp-input-paramsvideo8
struct rkisp_dmarx_device dmarx_dev;dma数据接收模块rkisp_rawrd0_m、rkisp_rawrd2_svideo5、video6
struct rkisp_csi_device csi_dev;csi的sub device从设备rkisp-csi-subdevv4l-subdev1
struct rkisp_bridge_device br_dev;桥接模块备,isp2.0中有--
enum rkisp_isp_ver isp_ver;isp版本号,rk3568是2.1--

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 :

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

#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

//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);……
}

一些关键的宏汇总:

//各个模块对应的名字
【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设备树节点属性说明参考内核说明文档:

[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通道中接收数据帧

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

千言万语,不如一图:

由上图可得:

  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)

文中各种mipi技术文档,后台回复关键字:mipi

后面还会继续更新几篇Camera文章,

建议大家订阅本专题!

也可以后台留言,加一口君好友yikoupeng,

拉你进高质量技术交流群。

相关内容

热门资讯

金榜题名主持词 金榜题名主持词(精选23篇)  主持词要根据活动对象的不同去设置不同的主持词。随着社会一步步向前发展...
光荣退休领导致辞 光荣退休领导致辞范文(通用5篇)  在学习、工作或生活中,要用到致辞的情况还是蛮多的,致辞是指在仪式...
大学迎新晚会主持词 大学迎新晚会主持词  迎新,全称迎接新春,又叫迎接新年。迎新是中国的传统节日形式。或者欢迎、迎接新来...
教师节校长简短致辞 教师节校长简短致辞(通用10篇)  在日常学习、工作抑或是生活中,大家或多或少都用到过致辞吧,在各种...
张国荣经典台词 关于张国荣经典台词  1、哭,我为了感动谁,笑,又为了碰着谁。  ——《路过蜻蜓》  2、虽然我很喜...
新郎婚礼简短致辞 新郎婚礼简短致辞(精选10篇)  在平平淡淡的学习、工作、生活中,大家都经常接触到致辞吧,致辞是指在...
美剧经典台词截图 美剧经典台词截图  在社会发展不断提速的今天,用到台词的地方越来越多,台词是一种特殊的文学语言,必须...
女朋友撒娇的经典台词 女朋友撒娇的经典台词  1、这种被朋友的情况让我很失落,因为我喜欢他。  2、“她就是躲着我我该怎么...
会主持词开场白 会主持词开场白  篇一  尊敬的各位领导、各位来宾  各位公司同仁:  大家下午好!  非常高兴和大...
中国人寿保险公司晨会主持词 中国人寿保险公司晨会主持词  主持词由主持人于节目进行过程中串联节目的串联词。以下是小编整理的中国人...
公司中秋晚会主持词 关于公司中秋晚会主持词  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在当今不断发展...
小学生职位竞选词 小学生职位竞选词  个人觉得竞选中队长,你已经很清楚中队长需要做的事情了,那么就从每一个任务来发展一...
在结婚典礼上的精彩幽默主持词 在结婚典礼上的精彩幽默主持词各位来宾:大家好!奉新郎新娘之命,我来主持今天的婚礼。为什么新郎新娘一定...
婚礼主持人搞笑台词 婚礼主持人搞笑台词  各位来宾:  大家好!奉新郎新娘之命,我来主持今天的婚礼,婚礼主持人搞笑台词。...
幼儿园运动会主持稿 幼儿园运动会主持稿  篇一:幼儿园运动会主持词  踏着春天的脚步,踩着春风的节拍,春天已经来到我们中...
小学庆元旦活动主持词 小学庆元旦活动主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在当今社会生活中,...
爵士舞蹈串词主持词   爵士舞即美国现代舞,是一种急促又富动感的节奏型舞蹈,是属于一种外放性的舞蹈,不像古典芭蕾舞或现代...
幼儿园元旦节目主持词   齐x:亲爱的爸爸妈妈  周x:亲爱的爷爷奶奶  王x:亲爱的老师  李x:亲爱的小朋友们  合:...
运动会运动员赞美词 运动会运动员赞美词1.赞运动员是我们的目标,是我们的信念,在清凉的初秋,在喧嚣的田径场上,。你们点燃...