.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * V4L2 Deinterlacer Subdev for Freescale i.MX5/6 SOC |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2017 Mentor Graphics Inc. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | | -#include <linux/delay.h> |
---|
12 | | -#include <linux/interrupt.h> |
---|
13 | | -#include <linux/module.h> |
---|
14 | | -#include <linux/platform_device.h> |
---|
15 | | -#include <linux/sched.h> |
---|
16 | | -#include <linux/slab.h> |
---|
17 | | -#include <linux/timer.h> |
---|
18 | 7 | #include <media/v4l2-ctrls.h> |
---|
19 | 8 | #include <media/v4l2-device.h> |
---|
20 | 9 | #include <media/v4l2-ioctl.h> |
---|
.. | .. |
---|
60 | 49 | /* |
---|
61 | 50 | * Min/Max supported width and heights. |
---|
62 | 51 | */ |
---|
63 | | -#define MIN_W 176 |
---|
64 | | -#define MIN_H 144 |
---|
| 52 | +#define MIN_W 32 |
---|
| 53 | +#define MIN_H 32 |
---|
65 | 54 | #define MAX_W_VDIC 968 |
---|
66 | 55 | #define MAX_H_VDIC 2048 |
---|
67 | 56 | #define W_ALIGN 4 /* multiple of 16 pixels */ |
---|
.. | .. |
---|
69 | 58 | #define S_ALIGN 1 /* multiple of 2 */ |
---|
70 | 59 | |
---|
71 | 60 | struct vdic_priv { |
---|
72 | | - struct device *dev; |
---|
73 | | - struct ipu_soc *ipu; |
---|
74 | | - struct imx_media_dev *md; |
---|
| 61 | + struct device *ipu_dev; |
---|
| 62 | + struct ipu_soc *ipu; |
---|
| 63 | + |
---|
75 | 64 | struct v4l2_subdev sd; |
---|
76 | 65 | struct media_pad pad[VDIC_NUM_PADS]; |
---|
77 | | - int ipu_id; |
---|
78 | 66 | |
---|
79 | 67 | /* lock to protect all members below */ |
---|
80 | 68 | struct mutex lock; |
---|
.. | .. |
---|
149 | 137 | struct ipuv3_channel *ch; |
---|
150 | 138 | struct ipu_vdi *vdi; |
---|
151 | 139 | |
---|
152 | | - priv->ipu = priv->md->ipu[priv->ipu_id]; |
---|
153 | | - |
---|
154 | 140 | vdi = ipu_vdi_get(priv->ipu); |
---|
155 | 141 | if (IS_ERR(vdi)) { |
---|
156 | 142 | v4l2_err(&priv->sd, "failed to get VDIC\n"); |
---|
.. | .. |
---|
219 | 205 | |
---|
220 | 206 | switch (priv->fieldtype) { |
---|
221 | 207 | case V4L2_FIELD_SEQ_TB: |
---|
222 | | - prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0); |
---|
223 | | - curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs; |
---|
224 | | - next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); |
---|
225 | | - break; |
---|
226 | 208 | case V4L2_FIELD_SEQ_BT: |
---|
227 | 209 | prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + fs; |
---|
228 | 210 | curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); |
---|
229 | 211 | next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs; |
---|
230 | 212 | break; |
---|
| 213 | + case V4L2_FIELD_INTERLACED_TB: |
---|
231 | 214 | case V4L2_FIELD_INTERLACED_BT: |
---|
| 215 | + case V4L2_FIELD_INTERLACED: |
---|
232 | 216 | prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + is; |
---|
233 | 217 | curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); |
---|
234 | 218 | next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is; |
---|
235 | 219 | break; |
---|
236 | 220 | default: |
---|
237 | | - /* assume V4L2_FIELD_INTERLACED_TB */ |
---|
238 | | - prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0); |
---|
239 | | - curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is; |
---|
240 | | - next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); |
---|
241 | | - break; |
---|
| 221 | + /* |
---|
| 222 | + * can't get here, priv->fieldtype can only be one of |
---|
| 223 | + * the above. This is to quiet smatch errors. |
---|
| 224 | + */ |
---|
| 225 | + return; |
---|
242 | 226 | } |
---|
243 | 227 | |
---|
244 | 228 | ipu_cpmem_set_buffer(priv->vdi_in_ch_p, 0, prev_phys); |
---|
.. | .. |
---|
263 | 247 | |
---|
264 | 248 | memset(&image, 0, sizeof(image)); |
---|
265 | 249 | image.pix = vdev->fmt.fmt.pix; |
---|
| 250 | + image.rect = vdev->compose; |
---|
266 | 251 | /* one field to VDIC channels */ |
---|
267 | 252 | image.pix.height /= 2; |
---|
268 | | - image.rect.width = image.pix.width; |
---|
269 | | - image.rect.height = image.pix.height; |
---|
| 253 | + image.rect.height /= 2; |
---|
270 | 254 | image.phys0 = phys0; |
---|
271 | 255 | image.phys1 = phys1; |
---|
272 | 256 | |
---|
.. | .. |
---|
517 | 501 | if (priv->stream_count != !enable) |
---|
518 | 502 | goto update_count; |
---|
519 | 503 | |
---|
520 | | - dev_dbg(priv->dev, "stream %s\n", enable ? "ON" : "OFF"); |
---|
| 504 | + dev_dbg(priv->ipu_dev, "%s: stream %s\n", sd->name, |
---|
| 505 | + enable ? "ON" : "OFF"); |
---|
521 | 506 | |
---|
522 | 507 | if (enable) |
---|
523 | 508 | ret = vdic_start(priv); |
---|
.. | .. |
---|
563 | 548 | if (code->pad >= VDIC_NUM_PADS) |
---|
564 | 549 | return -EINVAL; |
---|
565 | 550 | |
---|
566 | | - return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_YUV); |
---|
| 551 | + return imx_media_enum_ipu_formats(&code->code, code->index, |
---|
| 552 | + PIXFMT_SEL_YUV); |
---|
567 | 553 | } |
---|
568 | 554 | |
---|
569 | 555 | static int vdic_get_fmt(struct v4l2_subdev *sd, |
---|
.. | .. |
---|
598 | 584 | { |
---|
599 | 585 | struct v4l2_mbus_framefmt *infmt; |
---|
600 | 586 | |
---|
601 | | - *cc = imx_media_find_ipu_format(sdformat->format.code, CS_SEL_YUV); |
---|
| 587 | + *cc = imx_media_find_ipu_format(sdformat->format.code, |
---|
| 588 | + PIXFMT_SEL_YUV); |
---|
602 | 589 | if (!*cc) { |
---|
603 | 590 | u32 code; |
---|
604 | 591 | |
---|
605 | | - imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); |
---|
606 | | - *cc = imx_media_find_ipu_format(code, CS_SEL_YUV); |
---|
| 592 | + imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV); |
---|
| 593 | + *cc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV); |
---|
607 | 594 | sdformat->format.code = (*cc)->codes[0]; |
---|
608 | 595 | } |
---|
609 | 596 | |
---|
.. | .. |
---|
623 | 610 | &sdformat->format.height, |
---|
624 | 611 | MIN_H, MAX_H_VDIC, H_ALIGN, S_ALIGN); |
---|
625 | 612 | |
---|
626 | | - imx_media_fill_default_mbus_fields(&sdformat->format, infmt, |
---|
627 | | - true); |
---|
628 | | - |
---|
629 | 613 | /* input must be interlaced! Choose SEQ_TB if not */ |
---|
630 | 614 | if (!V4L2_FIELD_HAS_BOTH(sdformat->format.field)) |
---|
631 | 615 | sdformat->format.field = V4L2_FIELD_SEQ_TB; |
---|
632 | 616 | break; |
---|
633 | 617 | } |
---|
| 618 | + |
---|
| 619 | + imx_media_try_colorimetry(&sdformat->format, true); |
---|
634 | 620 | } |
---|
635 | 621 | |
---|
636 | 622 | static int vdic_set_fmt(struct v4l2_subdev *sd, |
---|
.. | .. |
---|
692 | 678 | struct v4l2_subdev *remote_sd; |
---|
693 | 679 | int ret = 0; |
---|
694 | 680 | |
---|
695 | | - dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name, |
---|
696 | | - local->entity->name); |
---|
| 681 | + dev_dbg(priv->ipu_dev, "%s: link setup %s -> %s", |
---|
| 682 | + sd->name, remote->entity->name, local->entity->name); |
---|
697 | 683 | |
---|
698 | 684 | mutex_lock(&priv->lock); |
---|
699 | 685 | |
---|
.. | .. |
---|
752 | 738 | remote_sd = media_entity_to_v4l2_subdev(remote->entity); |
---|
753 | 739 | |
---|
754 | 740 | /* direct pad must connect to a CSI */ |
---|
755 | | - if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_CSI) || |
---|
| 741 | + if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) || |
---|
756 | 742 | remote->index != CSI_SRC_PAD_DIRECT) { |
---|
757 | 743 | ret = -EINVAL; |
---|
758 | 744 | goto out; |
---|
.. | .. |
---|
826 | 812 | switch (fi->pad) { |
---|
827 | 813 | case VDIC_SINK_PAD_DIRECT: |
---|
828 | 814 | case VDIC_SINK_PAD_IDMAC: |
---|
829 | | - /* No limits on input frame interval */ |
---|
| 815 | + /* No limits on valid input frame intervals */ |
---|
| 816 | + if (fi->interval.numerator == 0 || |
---|
| 817 | + fi->interval.denominator == 0) |
---|
| 818 | + fi->interval = priv->frame_interval[fi->pad]; |
---|
830 | 819 | /* Reset output interval */ |
---|
831 | 820 | *output_fi = fi->interval; |
---|
832 | 821 | if (priv->csi_direct) |
---|
.. | .. |
---|
854 | 843 | return ret; |
---|
855 | 844 | } |
---|
856 | 845 | |
---|
857 | | -/* |
---|
858 | | - * retrieve our pads parsed from the OF graph by the media device |
---|
859 | | - */ |
---|
860 | 846 | static int vdic_registered(struct v4l2_subdev *sd) |
---|
861 | 847 | { |
---|
862 | 848 | struct vdic_priv *priv = v4l2_get_subdevdata(sd); |
---|
863 | 849 | int i, ret; |
---|
864 | 850 | u32 code; |
---|
865 | 851 | |
---|
866 | | - /* get media device */ |
---|
867 | | - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); |
---|
868 | | - |
---|
869 | 852 | for (i = 0; i < VDIC_NUM_PADS; i++) { |
---|
870 | | - priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ? |
---|
871 | | - MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; |
---|
872 | | - |
---|
873 | 853 | code = 0; |
---|
874 | 854 | if (i != VDIC_SINK_PAD_IDMAC) |
---|
875 | | - imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); |
---|
| 855 | + imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV); |
---|
876 | 856 | |
---|
877 | 857 | /* set a default mbus format */ |
---|
878 | 858 | ret = imx_media_init_mbus_fmt(&priv->format_mbus[i], |
---|
.. | .. |
---|
890 | 870 | |
---|
891 | 871 | priv->active_input_pad = VDIC_SINK_PAD_DIRECT; |
---|
892 | 872 | |
---|
893 | | - ret = vdic_init_controls(priv); |
---|
894 | | - if (ret) |
---|
895 | | - return ret; |
---|
896 | | - |
---|
897 | | - ret = media_entity_pads_init(&sd->entity, VDIC_NUM_PADS, priv->pad); |
---|
898 | | - if (ret) |
---|
899 | | - v4l2_ctrl_handler_free(&priv->ctrl_hdlr); |
---|
900 | | - |
---|
901 | | - return ret; |
---|
| 873 | + return vdic_init_controls(priv); |
---|
902 | 874 | } |
---|
903 | 875 | |
---|
904 | 876 | static void vdic_unregistered(struct v4l2_subdev *sd) |
---|
.. | .. |
---|
937 | 909 | .unregistered = vdic_unregistered, |
---|
938 | 910 | }; |
---|
939 | 911 | |
---|
940 | | -static int imx_vdic_probe(struct platform_device *pdev) |
---|
| 912 | +struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev, |
---|
| 913 | + struct device *ipu_dev, |
---|
| 914 | + struct ipu_soc *ipu, |
---|
| 915 | + u32 grp_id) |
---|
941 | 916 | { |
---|
942 | | - struct imx_media_internal_sd_platformdata *pdata; |
---|
943 | 917 | struct vdic_priv *priv; |
---|
944 | | - int ret; |
---|
| 918 | + int i, ret; |
---|
945 | 919 | |
---|
946 | | - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
---|
| 920 | + priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL); |
---|
947 | 921 | if (!priv) |
---|
948 | | - return -ENOMEM; |
---|
| 922 | + return ERR_PTR(-ENOMEM); |
---|
949 | 923 | |
---|
950 | | - platform_set_drvdata(pdev, &priv->sd); |
---|
951 | | - priv->dev = &pdev->dev; |
---|
952 | | - |
---|
953 | | - pdata = priv->dev->platform_data; |
---|
954 | | - priv->ipu_id = pdata->ipu_id; |
---|
| 924 | + priv->ipu_dev = ipu_dev; |
---|
| 925 | + priv->ipu = ipu; |
---|
955 | 926 | |
---|
956 | 927 | v4l2_subdev_init(&priv->sd, &vdic_subdev_ops); |
---|
957 | 928 | v4l2_set_subdevdata(&priv->sd, priv); |
---|
958 | 929 | priv->sd.internal_ops = &vdic_internal_ops; |
---|
959 | 930 | priv->sd.entity.ops = &vdic_entity_ops; |
---|
960 | 931 | priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; |
---|
961 | | - priv->sd.dev = &pdev->dev; |
---|
962 | | - priv->sd.owner = THIS_MODULE; |
---|
| 932 | + priv->sd.owner = ipu_dev->driver->owner; |
---|
963 | 933 | priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; |
---|
964 | | - /* get our group id */ |
---|
965 | | - priv->sd.grp_id = pdata->grp_id; |
---|
966 | | - strncpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); |
---|
| 934 | + priv->sd.grp_id = grp_id; |
---|
| 935 | + imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name), |
---|
| 936 | + priv->sd.grp_id, ipu_get_num(ipu)); |
---|
967 | 937 | |
---|
968 | 938 | mutex_init(&priv->lock); |
---|
969 | 939 | |
---|
970 | | - ret = v4l2_async_register_subdev(&priv->sd); |
---|
| 940 | + for (i = 0; i < VDIC_NUM_PADS; i++) |
---|
| 941 | + priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ? |
---|
| 942 | + MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; |
---|
| 943 | + |
---|
| 944 | + ret = media_entity_pads_init(&priv->sd.entity, VDIC_NUM_PADS, |
---|
| 945 | + priv->pad); |
---|
971 | 946 | if (ret) |
---|
972 | 947 | goto free; |
---|
973 | 948 | |
---|
974 | | - return 0; |
---|
| 949 | + ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd); |
---|
| 950 | + if (ret) |
---|
| 951 | + goto free; |
---|
| 952 | + |
---|
| 953 | + return &priv->sd; |
---|
975 | 954 | free: |
---|
976 | 955 | mutex_destroy(&priv->lock); |
---|
977 | | - return ret; |
---|
| 956 | + return ERR_PTR(ret); |
---|
978 | 957 | } |
---|
979 | 958 | |
---|
980 | | -static int imx_vdic_remove(struct platform_device *pdev) |
---|
| 959 | +int imx_media_vdic_unregister(struct v4l2_subdev *sd) |
---|
981 | 960 | { |
---|
982 | | - struct v4l2_subdev *sd = platform_get_drvdata(pdev); |
---|
983 | 961 | struct vdic_priv *priv = v4l2_get_subdevdata(sd); |
---|
984 | 962 | |
---|
985 | 963 | v4l2_info(sd, "Removing\n"); |
---|
986 | 964 | |
---|
987 | | - v4l2_async_unregister_subdev(sd); |
---|
| 965 | + v4l2_device_unregister_subdev(sd); |
---|
988 | 966 | mutex_destroy(&priv->lock); |
---|
989 | 967 | media_entity_cleanup(&sd->entity); |
---|
990 | 968 | |
---|
991 | 969 | return 0; |
---|
992 | 970 | } |
---|
993 | | - |
---|
994 | | -static const struct platform_device_id imx_vdic_ids[] = { |
---|
995 | | - { .name = "imx-ipuv3-vdic" }, |
---|
996 | | - { }, |
---|
997 | | -}; |
---|
998 | | -MODULE_DEVICE_TABLE(platform, imx_vdic_ids); |
---|
999 | | - |
---|
1000 | | -static struct platform_driver imx_vdic_driver = { |
---|
1001 | | - .probe = imx_vdic_probe, |
---|
1002 | | - .remove = imx_vdic_remove, |
---|
1003 | | - .id_table = imx_vdic_ids, |
---|
1004 | | - .driver = { |
---|
1005 | | - .name = "imx-ipuv3-vdic", |
---|
1006 | | - }, |
---|
1007 | | -}; |
---|
1008 | | -module_platform_driver(imx_vdic_driver); |
---|
1009 | | - |
---|
1010 | | -MODULE_DESCRIPTION("i.MX VDIC subdev driver"); |
---|
1011 | | -MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); |
---|
1012 | | -MODULE_LICENSE("GPL"); |
---|
1013 | | -MODULE_ALIAS("platform:imx-ipuv3-vdic"); |
---|