基于xilinx异构平台上视频采集分析

1.设备树结构

xilinx平台端

		vcap_csi {
			compatible = "xlnx,video";
			dmas = <&Video_IN_1ch_v_frmbuf_wr_0 0>;
			dma-names = "port0";
 
			ports {
				#address-cells = <1>;
				#size-cells = <0>;
 
				port@0 {
					reg = <0>;
					direction = "input";
 
					vcap_csi_in: endpoint {
						remote-endpoint = <&sensor_out>;
					};
				};
			};
		};

PL端的帧缓冲区 

		Video_IN_1ch_v_frmbuf_wr_0: v_frmbuf_wr@b0020000 {
			#dma-cells = <1>;
			clock-names = "ap_clk";
			clocks = <&clk 72>;
			compatible = "xlnx,v-frmbuf-wr-2.1", "xlnx,axi-frmbuf-wr-v2.1";
			interrupt-names = "interrupt";
			interrupt-parent = <&gic>;
			interrupts = <0 104 4>;
			reg = <0x0 0xb0020000 0x0 0x10000>;
			reset-gpios = <&gpio 80 1>;
			xlnx,dma-addr-width = <64>;
			xlnx,dma-align = <8>;
			xlnx,max-height = <2160>;
			xlnx,max-width = <3840>;
			xlnx,pixels-per-clock = <1>;
			xlnx,s-axi-ctrl-addr-width = <0x7>;
			xlnx,s-axi-ctrl-data-width = <0x20>;
			xlnx,vid-formats = "yuyv";
			xlnx,video-width = <8>;
		};

子设备驱动端: 

			nvp6124: sensor@1a{
				compatible = "nextchip,nvp6124";
				reg = <0x1a>;
				#address-cells = <1>;
				#size-cells = <0>;
 
				port@0 {
					reg = <0>;
 
					sensor_out: endpoint {
						remote-endpoint = <&vcap_csi_in>;
					};
				};
			};

2.源码分析

1)平台端

平台设备驱动与设备树匹配后执行probe函数,做如下操作:

 
static int xvip_graph_init(struct xvip_composite_device *xdev)
{
	struct xvip_graph_entity *entity;
	struct v4l2_async_subdev **subdevs = NULL;
	unsigned int num_subdevs;
	unsigned int i;
	int ret;
 
	/* Init the DMA channels. */
	ret = xvip_graph_dma_init(xdev);
	if (ret < 0) {
		dev_err(xdev->dev, "DMA initialization failed\n");
		goto done;
	}
 
	/* Parse the graph to extract a list of subdevice DT nodes. */
	ret = xvip_graph_parse(xdev);
	if (ret < 0) {
		dev_err(xdev->dev, "graph parsing failed\n");
		goto done;
	}
 
	if (!xdev->num_subdevs) {
		dev_err(xdev->dev, "no subdev found in graph\n");
		goto done;
	}
 
	/* Register the subdevices notifier. */
	num_subdevs = xdev->num_subdevs;
	subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs,
			       GFP_KERNEL);
	if (subdevs == NULL) {
		ret = -ENOMEM;
		goto done;
	}
 
	i = 0;
	list_for_each_entry(entity, &xdev->entities, list)
		subdevs[i++] = &entity->asd;
 
	xdev->notifier.subdevs = subdevs;
	xdev->notifier.num_subdevs = num_subdevs;
	xdev->notifier.bound = xvip_graph_notify_bound;
	xdev->notifier.complete = xvip_graph_notify_complete;
 
	ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
	if (ret < 0) {
		dev_err(xdev->dev, "notifier registration failed\n");
		goto done;
	}
 
	ret = 0;
 
done:
	if (ret < 0)
		xvip_graph_cleanup(xdev);
 
	return ret;
}

主要做了DMA通道初始化和v4l2_async_notifier_register

看一下v4l2_async_notifier_register做了什么工作;

 
int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
				 struct v4l2_async_notifier *notifier)
{
	struct v4l2_subdev *sd, *tmp;
	struct v4l2_async_subdev *asd;
	int i;
 
	if (!v4l2_dev || !notifier->num_subdevs ||
	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
		return -EINVAL;
 
	notifier->v4l2_dev = v4l2_dev;
	INIT_LIST_HEAD(&notifier->waiting);
	INIT_LIST_HEAD(&notifier->done);
 
	for (i = 0; i < notifier->num_subdevs; i++) {
		asd = notifier->subdevs[i];
 
		switch (asd->match_type) {
		case V4L2_ASYNC_MATCH_CUSTOM:
		case V4L2_ASYNC_MATCH_DEVNAME:
		case V4L2_ASYNC_MATCH_I2C:
		case V4L2_ASYNC_MATCH_FWNODE:
			break;
		default:
			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
				"Invalid match type %u on %p\n",
				asd->match_type, asd);
			return -EINVAL;
		}
		list_add_tail(&asd->list, &notifier->waiting);
	}
 
	mutex_lock(&list_lock);
	//获取是否有注册的subdev
	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
		int ret;
		printk("___________________v4l2_async_notifier_register___________notifier_list\n");
 
		asd = v4l2_async_belongs(notifier, sd);
		if (!asd)
			continue;
 
		ret = v4l2_async_test_notify(notifier, sd, asd);
		if (ret < 0) {
			mutex_unlock(&list_lock);
			return ret;
		}
	}
	printk("______________________________notifier_list\n");
 
	/* Keep also completed notifiers on the list */
	list_add(&notifier->list, &notifier_list);
 
	mutex_unlock(&list_lock);
 
	return 0;
}

假设子设备较晚匹配,则在链表中获取不到已有子设备注册,此时将该通知消息加入notifier_list链表中,待子设备驱动端获取;

若已有子设备注册,则会执行v4l2_async_test_notify函数;

 
static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
				  struct v4l2_subdev *sd,
				  struct v4l2_async_subdev *asd)
{
	int ret;
 
	if (notifier->bound) {
		ret = notifier->bound(notifier, sd, asd);
		if (ret < 0)
			return ret;
	}
 
	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
	if (ret < 0) {
		if (notifier->unbind)
			notifier->unbind(notifier, sd, asd);
		return ret;
	}
 
	/* Remove from the waiting list */
	list_del(&asd->list);
	sd->asd = asd;
	sd->notifier = notifier;
 
	/* Move from the global subdevice list to notifier's done */
	list_move(&sd->async_list, &notifier->done);
 
	if (list_empty(&notifier->waiting) && notifier->complete)
		return notifier->complete(notifier);
 
	return 0;
}

这里回调bound和执行v4l2_device_register_subdev把子设备注册到V4L2核心层;

2)子设备端

通过v4l2_async_register_subdev注册;

 
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *notifier;
 
	/*
	 * No reference taken. The reference is held by the device
	 * (struct v4l2_subdev.dev), and async sub-device does not
	 * exist independently of the device at any point of time.
	 */
	if (!sd->fwnode && sd->dev)
		sd->fwnode = dev_fwnode(sd->dev);
 
	mutex_lock(&list_lock);
 
	INIT_LIST_HEAD(&sd->async_list);
	//查找是否平台已注册了通知subdev事件,紧接着将执行注册v4l2_device_register_subdev
	list_for_each_entry(notifier, &notifier_list, list) {
		printk("______________________v4l2_async_register_subdev___________notifier_list\n");
		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
		if (asd) {
			int ret = v4l2_async_test_notify(notifier, sd, asd);
			mutex_unlock(&list_lock);
			return ret;
		}
	}
 
	/* None matched, wait for hot-plugging */
	list_add(&sd->async_list, &subdev_list);
 
	mutex_unlock(&list_lock);
 
	return 0;
}

这里操作与上面v4l2_async_notifier_register互补关系;不管谁先谁后注册,最后都将实现v4l2_async_test_notify函数操作;

猜你喜欢

转载自blog.csdn.net/a8039974/article/details/107726115