Linux v4l2子系统(7):CIF(VICAP)
关键词:CIF、Interface、Crop、MUX、Scale、IOMMU、MIPI、PVDS、DVP等等。
1 VICAP框架图
VICAP负责从DVP/MIPI接收数据,将数据通过AXI存入内存,或者直接送到ISP,包括如下组件:
- Interface:和DVP/MIPI CSI接口对接,共7个。
- Crop:负责对输入的数据进行裁剪。
- MUX:负责将数据送到不同ISP通道。
- Scale:对数据进行缩小,共4个。
- DMA:负责对DVP/MIPI/Scale数据搬运,共8个。
2 VICAP驱动
2.1 RKCIF
RKCIF对应的硬件模块为VICAP,负责从DVP/MIPI获取数据并存入内存。
rkcif: rkcif@fdce0000 { compatible = "rockchip,rk3588-cif"; reg = <0x0 0xfdce0000 0x0 0x800>; reg-names = "cif_regs"; interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "cif-intr"; clocks = <&cru ACLK_VICAP>, <&cru HCLK_VICAP>, <&cru DCLK_VICAP>; clock-names = "aclk_cif", "hclk_cif", "dclk_cif"; resets = <&cru SRST_A_VICAP>, <&cru SRST_H_VICAP>, <&cru SRST_D_VICAP>; reset-names = "rst_cif_a", "rst_cif_h", "rst_cif_d"; assigned-clocks = <&cru DCLK_VICAP>; assigned-clock-rates = <600000000>; power-domains = <&power RK3588_PD_VI>; rockchip,grf = <&sys_grf>; iommus = <&rkcif_mmu>; status = "disabled"; };
RK CIF即VICAP设备:
rk_cif_plat_drv_init
platform_driver_register
rkcif_hw_plat_drv
rkcif_plat_hw_probe
->rkcif_irq_handler--VICAP的中断处理程序。
->从dts中获取信息,填充并初始化struct rkcif_hw结构体。
->rkcif_plat_drv--匹配"rockchip,rkcif-mipi-lvds"进行
->rkcif_subdev_driver--
rkcif_csi2_plat_drv_init--初始化CSI2。
2.2 RKCIF IOMMU
选用IOMMU作为RKCIF的MMU:
rkcif_mmu: iommu@fdce0800 { compatible = "rockchip,iommu-v2"; reg = <0x0 0xfdce0800 0x0 0x100>, <0x0 0xfdce0900 0x0 0x100>; interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "cif_mmu"; clocks = <&cru ACLK_VICAP>, <&cru HCLK_VICAP>; clock-names = "aclk", "iface"; power-domains = <&power RK3588_PD_VI>; rockchip,disable-mmu-reset; #iommu-cells = <0>; status = "disabled"; };
rk_iommu_init进行IOMMU的初始化:
rk_iommu_init
rk_iommu_driver
rk_iommu_probe
->获取寄存器、中断、clock、power等资源。
iommu_group_alloc
iommu_device_sysfs_add
iommu_device_register
2.3 RKCIF MIPI_LVDS
RKCIF MIPI LVDS作为VICAP的一个通道,支持MIPI/LVDS数据搬运:
- 对应的应将为rkcif,使用iommu作为MMU。
- Sink Pad来自于CSI2 Host的mipi2_csi2_output。
rkcif_mipi_lvds2: rkcif-mipi-lvds2 {
compatible = "rockchip,rkcif-mipi-lvds";
rockchip,hw = <&rkcif>;
iommus = <&rkcif_mmu>;
status = "disabled";
};
&rkcif_mipi_lvds2 {
status = "okay";
port {
cif_mipi2_in0: endpoint {
remote-endpoint = <&mipi2_csi2_output>;
};
};
};
rkcif_plat_drv进行rkcif一个通道的初始化:
- 获取硬件和MMU设备。
- 初始化Stream、Scale、Tools设备。
- 创建一系列v4l2设备。
- 创建proc节点。
rkcif_plat_drv
->rkcif_plat_probe
->sysfs_create_group--创建一系列sysfs属性节点。
->rkcif_attach_hw--查找"rockchip,hw"对应数据结构,将其和struct rkcif_device匹配。
->rkcif_parse_dts--获取"wait-line"值。
->rkcif_plat_init
->rkcif_stream_init--初始化rkcif_stream设备。
->rkcif_init_scale_vdev--rkcif_scale_vdev初始化rkcif_scale_vdev设备。
->rkcif_init_tools_vdev--初始化rkcif_tools_vdev设备。
->v4l2_device_register
->media_device_init
->media_device_register
->rkcif_register_platform_subdevs
->rkcif_register_stream_vdevs--创建设备位于/sys/devices/platform/rkcif-mipi-lvds2/video4linux/videoX,共4个。
->rkcif_register_stream_vdev--依次创建4个RKCIF_STREAM_MIPI_IDx设备。
->rkcif_init_vb2_queue--初始化struct vb2_queue。
->video_register_device--注册v4l2设备,操作函数集为rkcif_fops和rkcif_v4l2_ioctl_ops。
->media_entity_pads_init--初始化一个Sink Pad。
->rkcif_register_scale_vdevs--对应VICAP的4个Scale设备,创建设备位于/sys/devices/platform/rkcif-mipi-lvds2/video4linux/videox。
->rkcif_register_scale_vdev--依次创建4个RKCIF_SCALE_CHx设备。
->rkcif_scale_init_vb2_queue
->media_entity_pads_init
->video_register_device--注册v4l2设备,操作函数集为rkcif_scale_fops和rkcif_scale_ioctl。
->rkcif_register_tools_vdevs
->rkcif_register_tools_vdev--依次创建3个RKCIF_TOOLS_CHx设备。
->rkcif_tools_init_vb2_queue
->media_entity_pads_init
->video_register_device--注册v4l2设备,操作函数集为rkcif_tools_fops和rkcif_tools_ioctl。
->cif_subdev_notifier
->v4l2_async_notifier_init
->v4l2_async_notifier_parse_fwnode_endpoints--解析/rkcif-mipi-lvds2/port下的endpoint。
->v4l2_async_notifier_register
->rkcif_register_luma_vdev
->rkcif_get_reserved_mem
->rkcif_proc_init--创建/proc/rkcif-mipi-lvds2,显示当前设备信息。
->rkcif_init_reset_monitor
rkcif_mipi_lvds2设备:
- 为4个Stream设备,在v4l2子系统创建4个/dev/videoX设备;在Media子系统创建stream_cif_mipi_idX Entity,每个Entity包含一个Sink Pad。
- 为4个Scale设备,在v4l2子系统创建4个/dev/videoX设备;在Media子系统创建rkcif_scale_chX Entity,每个Entity包含一个Sink Pad。
- 为3个Tools设备,在v4l2子系统创建3个/dev/videoX设备;在Media子系统创建rkcif_tools_idX Entity,每个Entity包含一个Sink Pad。
2.4 RKCIF MIPI LVDS SDITF
RKCIF MIPI LVDS SDITF是基于RKCIF MIPI LCDS虚拟出来的设备,指明和ISP的链路关系。
rkcif_mipi_lvds2_sditf: rkcif-mipi-lvds2-sditf {
compatible = "rockchip,rkcif-sditf";
rockchip,cif = <&rkcif_mipi_lvds2>;
status = "disabled";
};
&rkcif_mipi_lvds2_sditf {
status = "okay";
port {
mipi_lvds2_sditf: endpoint {
remote-endpoint = <&isp0_vir0>;
};
};
};
rkcif_subdev_probe进行rkcif_mipi_lvds2_sditf设备初始化,和硬件设备rkcif_mipi_lvds2绑定:
rkcif_subdev_driver ->rkcif_subdev_probe
->初始化v4l2_subdev设备,V4L2_SUBDEV_FL_HAS_DEVNODE表示创建设备节点。 ->v4l2_subdev_init--操作函数集为sditf_subdev_ops。 ->rkcif_sditf_attach_cifdev--将rkcif_mipi_lvds2附着到此设备。 ->rkcif_subdev_media_init
->media_entity_pads_init--紧创建一个Source Pad。
->v4l2_ctrl_new_std--创建V4L2_CID_PIXEL_RATE Control。
对应的操作函数集如下:
static const struct v4l2_subdev_pad_ops sditf_subdev_pad_ops = { .set_fmt = sditf_get_set_fmt, .get_fmt = sditf_get_set_fmt, .get_selection = sditf_get_selection, .get_mbus_config = sditf_g_mbus_config, }; static const struct v4l2_subdev_video_ops sditf_video_ops = { .g_frame_interval = sditf_g_frame_interval, .s_stream = sditf_s_stream, .s_rx_buffer = sditf_s_rx_buffer, }; static const struct v4l2_subdev_core_ops sditf_core_ops = { .ioctl = sditf_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl32 = sditf_compat_ioctl32, #endif .s_power = sditf_s_power, }; static const struct v4l2_subdev_ops sditf_subdev_ops = { .core = &sditf_core_ops, .video = &sditf_video_ops, .pad = &sditf_subdev_pad_ops, };
rkcif_mipi_lvds2_sditf设备:
- 对应的v4l2设备为/dev/v4l-subdev4,对应的操作函数为stdif_subdev_ops。
- 在Media子系统中对应的Entity为rkcif-mipi-lvds2,仅包含一个Source Pad到ISP。
联系方式:arnoldlu@qq.com