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

- 日理万妓 2023-02-08 14:30 19阅读 0赞

1.设备树结构

xilinx平台端

  1. vcap_csi {
  2. compatible = "xlnx,video";
  3. dmas = <&Video_IN_1ch_v_frmbuf_wr_0 0>;
  4. dma-names = "port0";
  5. ports {
  6. #address-cells = <1>;
  7. #size-cells = <0>;
  8. port@0 {
  9. reg = <0>;
  10. direction = "input";
  11. vcap_csi_in: endpoint {
  12. remote-endpoint = <&sensor_out>;
  13. };
  14. };
  15. };
  16. };

PL端的帧缓冲区

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

子设备驱动端:

  1. nvp6124: sensor@1a{
  2. compatible = "nextchip,nvp6124";
  3. reg = <0x1a>;
  4. #address-cells = <1>;
  5. #size-cells = <0>;
  6. port@0 {
  7. reg = <0>;
  8. sensor_out: endpoint {
  9. remote-endpoint = <&vcap_csi_in>;
  10. };
  11. };
  12. };

2.源码分析

1)平台端

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

  1. static int xvip_graph_init(struct xvip_composite_device *xdev)
  2. {
  3. struct xvip_graph_entity *entity;
  4. struct v4l2_async_subdev **subdevs = NULL;
  5. unsigned int num_subdevs;
  6. unsigned int i;
  7. int ret;
  8. /* Init the DMA channels. */
  9. ret = xvip_graph_dma_init(xdev);
  10. if (ret < 0) {
  11. dev_err(xdev->dev, "DMA initialization failed\n");
  12. goto done;
  13. }
  14. /* Parse the graph to extract a list of subdevice DT nodes. */
  15. ret = xvip_graph_parse(xdev);
  16. if (ret < 0) {
  17. dev_err(xdev->dev, "graph parsing failed\n");
  18. goto done;
  19. }
  20. if (!xdev->num_subdevs) {
  21. dev_err(xdev->dev, "no subdev found in graph\n");
  22. goto done;
  23. }
  24. /* Register the subdevices notifier. */
  25. num_subdevs = xdev->num_subdevs;
  26. subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs,
  27. GFP_KERNEL);
  28. if (subdevs == NULL) {
  29. ret = -ENOMEM;
  30. goto done;
  31. }
  32. i = 0;
  33. list_for_each_entry(entity, &xdev->entities, list)
  34. subdevs[i++] = &entity->asd;
  35. xdev->notifier.subdevs = subdevs;
  36. xdev->notifier.num_subdevs = num_subdevs;
  37. xdev->notifier.bound = xvip_graph_notify_bound;
  38. xdev->notifier.complete = xvip_graph_notify_complete;
  39. ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
  40. if (ret < 0) {
  41. dev_err(xdev->dev, "notifier registration failed\n");
  42. goto done;
  43. }
  44. ret = 0;
  45. done:
  46. if (ret < 0)
  47. xvip_graph_cleanup(xdev);
  48. return ret;
  49. }

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

看一下v4l2_async_notifier_register做了什么工作;

  1. int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
  2. struct v4l2_async_notifier *notifier)
  3. {
  4. struct v4l2_subdev *sd, *tmp;
  5. struct v4l2_async_subdev *asd;
  6. int i;
  7. if (!v4l2_dev || !notifier->num_subdevs ||
  8. notifier->num_subdevs > V4L2_MAX_SUBDEVS)
  9. return -EINVAL;
  10. notifier->v4l2_dev = v4l2_dev;
  11. INIT_LIST_HEAD(&notifier->waiting);
  12. INIT_LIST_HEAD(&notifier->done);
  13. for (i = 0; i < notifier->num_subdevs; i++) {
  14. asd = notifier->subdevs[i];
  15. switch (asd->match_type) {
  16. case V4L2_ASYNC_MATCH_CUSTOM:
  17. case V4L2_ASYNC_MATCH_DEVNAME:
  18. case V4L2_ASYNC_MATCH_I2C:
  19. case V4L2_ASYNC_MATCH_FWNODE:
  20. break;
  21. default:
  22. dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
  23. "Invalid match type %u on %p\n",
  24. asd->match_type, asd);
  25. return -EINVAL;
  26. }
  27. list_add_tail(&asd->list, &notifier->waiting);
  28. }
  29. mutex_lock(&list_lock);
  30. //获取是否有注册的subdev
  31. list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
  32. int ret;
  33. printk("___________________v4l2_async_notifier_register___________notifier_list\n");
  34. asd = v4l2_async_belongs(notifier, sd);
  35. if (!asd)
  36. continue;
  37. ret = v4l2_async_test_notify(notifier, sd, asd);
  38. if (ret < 0) {
  39. mutex_unlock(&list_lock);
  40. return ret;
  41. }
  42. }
  43. printk("______________________________notifier_list\n");
  44. /* Keep also completed notifiers on the list */
  45. list_add(&notifier->list, &notifier_list);
  46. mutex_unlock(&list_lock);
  47. return 0;
  48. }

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

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

  1. static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
  2. struct v4l2_subdev *sd,
  3. struct v4l2_async_subdev *asd)
  4. {
  5. int ret;
  6. if (notifier->bound) {
  7. ret = notifier->bound(notifier, sd, asd);
  8. if (ret < 0)
  9. return ret;
  10. }
  11. ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
  12. if (ret < 0) {
  13. if (notifier->unbind)
  14. notifier->unbind(notifier, sd, asd);
  15. return ret;
  16. }
  17. /* Remove from the waiting list */
  18. list_del(&asd->list);
  19. sd->asd = asd;
  20. sd->notifier = notifier;
  21. /* Move from the global subdevice list to notifier's done */
  22. list_move(&sd->async_list, &notifier->done);
  23. if (list_empty(&notifier->waiting) && notifier->complete)
  24. return notifier->complete(notifier);
  25. return 0;
  26. }

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

2)子设备端

通过v4l2_async_register_subdev注册;

  1. int v4l2_async_register_subdev(struct v4l2_subdev *sd)
  2. {
  3. struct v4l2_async_notifier *notifier;
  4. /*
  5. * No reference taken. The reference is held by the device
  6. * (struct v4l2_subdev.dev), and async sub-device does not
  7. * exist independently of the device at any point of time.
  8. */
  9. if (!sd->fwnode && sd->dev)
  10. sd->fwnode = dev_fwnode(sd->dev);
  11. mutex_lock(&list_lock);
  12. INIT_LIST_HEAD(&sd->async_list);
  13. //查找是否平台已注册了通知subdev事件,紧接着将执行注册v4l2_device_register_subdev
  14. list_for_each_entry(notifier, &notifier_list, list) {
  15. printk("______________________v4l2_async_register_subdev___________notifier_list\n");
  16. struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
  17. if (asd) {
  18. int ret = v4l2_async_test_notify(notifier, sd, asd);
  19. mutex_unlock(&list_lock);
  20. return ret;
  21. }
  22. }
  23. /* None matched, wait for hot-plugging */
  24. list_add(&sd->async_list, &subdev_list);
  25. mutex_unlock(&list_lock);
  26. return 0;
  27. }

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

发表评论

表情:
评论列表 (有 0 条评论,19人围观)

还没有评论,来说两句吧...

相关阅读