基于xilinx异构平台上视频采集分析
生活随笔
收集整理的這篇文章主要介紹了
基于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(¬ifier->waiting);INIT_LIST_HEAD(¬ifier->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, ¬ifier->waiting);}mutex_lock(&list_lock);//獲取是否有注冊的subdevlist_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(¬ifier->list, ¬ifier_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, ¬ifier->done);if (list_empty(¬ifier->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_subdevlist_for_each_entry(notifier, ¬ifier_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函數操作;
總結
以上是生活随笔為你收集整理的基于xilinx异构平台上视频采集分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 比亚迪宋110旗舰plus的对外放电的功
- 下一篇: 2.4八代雅阁启动后延迟几秒机油灯熄灭?