3c881a1bfc159916ce83c563eeedf88324d64b30
[oweals/openwrt.git] /
1 From 94d77466473f3abcf799ac44b8038766ab32f27c Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 16 Oct 2019 18:53:06 +0100
4 Subject: [PATCH] media: bcm2835-unicam: Fix one-to-many mapping for
5  YUYV formats
6
7 V4L2 format V4L2_PIX_FMT_YUYV maps to both MEDIA_BUS_FMT_YUYV8_2X8
8 and MEDIA_BUS_FMT_YUYV8_1X16. The change to not cache the active
9 formats also meant that we only ever found the first variant of
10 the mediabus format when trying to setup the device.
11
12 Flag the formats that have other representations, and ensure
13 that the format conversion checks whether the found format
14 matches one supported by the sensor before returning it.
15
16 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
17 ---
18  .../media/platform/bcm2835/bcm2835-unicam.c   | 45 ++++++++++++++++---
19  1 file changed, 39 insertions(+), 6 deletions(-)
20
21 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
22 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
23 @@ -136,6 +136,8 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
24   * @code: V4L2 media bus format code.
25   * @depth: Bits per pixel as delivered from the source.
26   * @csi_dt: CSI data type.
27 + * @check_variants: Flag to denote that there are multiple mediabus formats
28 + *             still in the list that could match this V4L2 format.
29   */
30  struct unicam_fmt {
31         u32     fourcc;
32 @@ -143,6 +145,7 @@ struct unicam_fmt {
33         u32     code;
34         u8      depth;
35         u8      csi_dt;
36 +       u8      check_variants;
37  };
38  
39  static const struct unicam_fmt formats[] = {
40 @@ -152,21 +155,25 @@ static const struct unicam_fmt formats[]
41                 .code           = MEDIA_BUS_FMT_YUYV8_2X8,
42                 .depth          = 16,
43                 .csi_dt         = 0x1e,
44 +               .check_variants = 1,
45         }, {
46                 .fourcc         = V4L2_PIX_FMT_UYVY,
47                 .code           = MEDIA_BUS_FMT_UYVY8_2X8,
48                 .depth          = 16,
49                 .csi_dt         = 0x1e,
50 +               .check_variants = 1,
51         }, {
52                 .fourcc         = V4L2_PIX_FMT_YVYU,
53                 .code           = MEDIA_BUS_FMT_YVYU8_2X8,
54                 .depth          = 16,
55                 .csi_dt         = 0x1e,
56 +               .check_variants = 1,
57         }, {
58                 .fourcc         = V4L2_PIX_FMT_VYUY,
59                 .code           = MEDIA_BUS_FMT_VYUY8_2X8,
60                 .depth          = 16,
61                 .csi_dt         = 0x1e,
62 +               .check_variants = 1,
63         }, {
64                 .fourcc         = V4L2_PIX_FMT_YUYV,
65                 .code           = MEDIA_BUS_FMT_YUYV8_1X16,
66 @@ -489,14 +496,40 @@ static const struct unicam_fmt *find_for
67         return NULL;
68  }
69  
70 -static const struct unicam_fmt *find_format_by_pix(u32 pixelformat)
71 +static int check_mbus_format(struct unicam_device *dev,
72 +                            const struct unicam_fmt *format)
73 +{
74 +       struct v4l2_subdev_mbus_code_enum mbus_code;
75 +       int ret = 0;
76 +       int i;
77 +
78 +       for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
79 +               memset(&mbus_code, 0, sizeof(mbus_code));
80 +               mbus_code.index = i;
81 +
82 +               ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
83 +                                      NULL, &mbus_code);
84 +
85 +               if (!ret && mbus_code.code == format->code)
86 +                       return 1;
87 +       }
88 +
89 +       return 0;
90 +}
91 +
92 +static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
93 +                                                  u32 pixelformat)
94  {
95         unsigned int k;
96  
97         for (k = 0; k < ARRAY_SIZE(formats); k++) {
98                 if (formats[k].fourcc == pixelformat ||
99 -                   formats[k].repacked_fourcc == pixelformat)
100 +                   formats[k].repacked_fourcc == pixelformat) {
101 +                       if (formats[k].check_variants &&
102 +                           !check_mbus_format(dev, &formats[k]))
103 +                               continue;
104                         return &formats[k];
105 +               }
106         }
107  
108         return NULL;
109 @@ -832,7 +865,7 @@ static int unicam_try_fmt_vid_cap(struct
110         struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
111         int ret;
112  
113 -       fmt = find_format_by_pix(f->fmt.pix.pixelformat);
114 +       fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
115         if (!fmt) {
116                 /* Pixel format not supported by unicam. Choose the first
117                  * supported format, and let the sensor choose something else.
118 @@ -917,7 +950,7 @@ static int unicam_s_fmt_vid_cap(struct f
119         if (ret < 0)
120                 return ret;
121  
122 -       fmt = find_format_by_pix(f->fmt.pix.pixelformat);
123 +       fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
124         if (!fmt) {
125                 /* Unknown pixel format - adopt a default.
126                  * This shouldn't happen as try_fmt should have resolved any
127 @@ -1540,7 +1573,7 @@ static int unicam_enum_framesizes(struct
128         int ret;
129  
130         /* check for valid format */
131 -       fmt = find_format_by_pix(fsize->pixel_format);
132 +       fmt = find_format_by_pix(dev, fsize->pixel_format);
133         if (!fmt) {
134                 unicam_dbg(3, dev, "Invalid pixel code: %x\n",
135                            fsize->pixel_format);
136 @@ -1579,7 +1612,7 @@ static int unicam_enum_frameintervals(st
137         };
138         int ret;
139  
140 -       fmt = find_format_by_pix(fival->pixel_format);
141 +       fmt = find_format_by_pix(dev, fival->pixel_format);
142         if (!fmt)
143                 return -EINVAL;
144