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,

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

相关内容

热门资讯

我只想爱着你爱情诗歌 我只想爱着你爱情诗歌  当你回头时  我还会在你身后默默等待着你  也许是细雨  滴入了我的心里  ...
交通安全诗歌 交通安全诗歌大全  在平时的学习、工作或生活中,大家都接触过诗歌吧,诗歌能使人们自然而然地受到语言的...
北岛的诗歌课(2) 北岛的诗歌课  在消失的危险上  在没有记忆的希望中  我写下你的名字  凭借一个词的力量  我重新...
描写夏天景色的古诗句   描写夏天景色的古诗句有哪一些呢?下面是小编收集整理的描写夏天景色的古诗句,欢迎阅读参考!!  描...
爱的深处是苦涩现代诗歌 爱的深处是苦涩现代诗歌  一、荷  你走出淤泥  走进清涟  你走出清涟  又走进阳光  同时也走进...
三月正当三十日,占得,春光毕... “三月正当三十日,占得,春光毕竟共春归。”出处 出自 清代 庄棫 的《定风波·为有书来与我期》“三月...
苏轼《定风波》全诗及赏析 苏轼《定风波》全诗及赏析  苏轼是北宋时期卓有贡献的词人,他在创作实践中,全面继承了前人词作的题材范...
描写月的诗句 描写月的诗句  在日常学习、工作抑或是生活中,许多人对一些广为流传的诗句都不陌生吧,诗句具有音韵和谐...
绝句志南和尚古诗 绝句志南和尚古诗  在日常的学习、工作、生活中,许多人都接触过一些比较经典的古诗吧,汉魏以后的古诗一...
马年春节诗词名句 马年春节诗词名句  马年春节诗词名句  1).团团圆圆你的心,春节佳节事事新,快快乐乐你的家,红红火...
赌胜马蹄下,由来轻七尺 “赌胜马蹄下,由来轻七尺。”出处 出自 唐代 李颀 的《古意》“赌胜马蹄下,由来轻七尺。”全诗《古意...
韦庄《应天长》“别来半岁音书... 应天长韦庄别来半岁音书绝⑴,一寸离肠千万结⑵。难相见,易相别,又是玉楼花似雪⑶。暗相思,无处说,惆怅...
形容秋天的古诗 形容秋天的古诗  在日复一日的学习、工作或生活中,大家或多或少都接触过一些经典的古诗吧,古诗作为一种...
杜甫的诗全集 杜甫的诗全集  1.望岳 [杜甫]  2.登楼 [杜甫]  3.题张氏隐居 [杜甫]  4.玉台观 ...
唐代王维的《鸟鸣涧》 唐代王维的《鸟鸣涧》  原文:人闲桂花落,夜静春山空。月出惊山鸟,时鸣春涧中。  整首诗的意思是不用...
描写小满的诗句 描写小满的诗句  《归田园四时乐春夏二首(其二)》  [宋 欧阳修]  南风原头吹百草,草木丛深茅舍...
王维律诗 王维精选十首律诗  导语:唐代诗人王维有盛唐律诗第一高手之称,下面是小编精选的`王维的十首律诗,供大...
于赞美母亲的诗句 于赞美母亲的诗句  阿母亲教学步虚,三元长遣下蓬壶。云韶韵俗停瑶瑟,鸾鹤飞低拂宝炉。 《步虚》【唐】...
太息,太息陆游,太息的意思,... 太息,太息陆游,太息的意思,太息赏析 -诗词大全 太息 作者:陆游朝代:南宋 北陌东阡有故...
《游山西村》全诗赏析 《游山西村》全诗赏析  在我们平凡无奇的学生时代,大家都背过不少知识点,肯定对知识点非常熟悉吧!知识...