199c4961e867b8f4b6596af51847d4aac3560cc8
[oweals/openwrt.git] /
1 From 5ae0488f5fc682877ae2a5d454f70884e62120ef Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Thu, 3 Oct 2019 13:35:01 +0100
4 Subject: [PATCH] media: bcm2835-unicam: Support unpacking CSI format
5  to 16bpp
6
7 The CSI packed formats are not the easiest to work with, and
8 the peripheral supports unpacking them to 16bpp (but NOT
9 shifting the data up into the MSBs).
10 Where V4L2 exposes a pixfmt for both packed and unpacked
11 formats advertise both as being supported, and unpack the
12 data in the peripheral.
13
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
15 ---
16  .../media/platform/bcm2835/bcm2835-unicam.c   | 102 +++++++++---------
17  1 file changed, 51 insertions(+), 51 deletions(-)
18
19 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
20 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
21 @@ -15,12 +15,15 @@
22   *
23   * This driver directly controls the Unicam peripheral - there is no
24   * involvement with the VideoCore firmware. Unicam receives CSI-2 or
25 - * CCP2 data and writes it into SDRAM. The only potential processing options are
26 - * to repack Bayer data into an alternate format, and applying windowing.
27 - * The repacking does not shift the data, so could repack V4L2_PIX_FMT_Sxxxx10P
28 + * CCP2 data and writes it into SDRAM.
29 + * The only potential processing options are to repack Bayer data into an
30 + * alternate format, and applying windowing.
31 + * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
32   * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
33 - * but not generically up to V4L2_PIX_FMT_Sxxxx16.
34 - * Adding support for repacking and windowing may be added later.
35 + * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
36 + * formats where the relevant formats are defined, and will automatically
37 + * configure the repacking as required.
38 + * Support for windowing may be added later.
39   *
40   * It should be possible to connect this driver to any sensor with a
41   * suitable output interface and V4L2 subdevice driver.
42 @@ -122,13 +125,16 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
43  
44  /*
45   * struct unicam_fmt - Unicam media bus format information
46 - * @pixelformat: V4L2 pixel format FCC identifier.
47 + * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
48 + * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
49 + * out to 16bpp. 0 if n/a.
50   * @code: V4L2 media bus format code.
51 - * @depth: Bits per pixel (when stored in memory).
52 + * @depth: Bits per pixel as delivered from the source.
53   * @csi_dt: CSI data type.
54   */
55  struct unicam_fmt {
56         u32     fourcc;
57 +       u32     repacked_fourcc;
58         u32     code;
59         u8      depth;
60         u8      csi_dt;
61 @@ -235,41 +241,49 @@ static const struct unicam_fmt formats[]
62                 .csi_dt         = 0x2a,
63         }, {
64                 .fourcc         = V4L2_PIX_FMT_SBGGR10P,
65 +               .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
66                 .code           = MEDIA_BUS_FMT_SBGGR10_1X10,
67                 .depth          = 10,
68                 .csi_dt         = 0x2b,
69         }, {
70                 .fourcc         = V4L2_PIX_FMT_SGBRG10P,
71 +               .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
72                 .code           = MEDIA_BUS_FMT_SGBRG10_1X10,
73                 .depth          = 10,
74                 .csi_dt         = 0x2b,
75         }, {
76                 .fourcc         = V4L2_PIX_FMT_SGRBG10P,
77 +               .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
78                 .code           = MEDIA_BUS_FMT_SGRBG10_1X10,
79                 .depth          = 10,
80                 .csi_dt         = 0x2b,
81         }, {
82                 .fourcc         = V4L2_PIX_FMT_SRGGB10P,
83 +               .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
84                 .code           = MEDIA_BUS_FMT_SRGGB10_1X10,
85                 .depth          = 10,
86                 .csi_dt         = 0x2b,
87         }, {
88                 .fourcc         = V4L2_PIX_FMT_SBGGR12P,
89 +               .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
90                 .code           = MEDIA_BUS_FMT_SBGGR12_1X12,
91                 .depth          = 12,
92                 .csi_dt         = 0x2c,
93         }, {
94                 .fourcc         = V4L2_PIX_FMT_SGBRG12P,
95 +               .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
96                 .code           = MEDIA_BUS_FMT_SGBRG12_1X12,
97                 .depth          = 12,
98                 .csi_dt         = 0x2c,
99         }, {
100                 .fourcc         = V4L2_PIX_FMT_SGRBG12P,
101 +               .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
102                 .code           = MEDIA_BUS_FMT_SGRBG12_1X12,
103                 .depth          = 12,
104                 .csi_dt         = 0x2c,
105         }, {
106                 .fourcc         = V4L2_PIX_FMT_SRGGB12P,
107 +               .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
108                 .code           = MEDIA_BUS_FMT_SRGGB12_1X12,
109                 .depth          = 12,
110                 .csi_dt         = 0x2c,
111 @@ -439,20 +453,6 @@ static inline void unicam_runtime_put(st
112  }
113  
114  /* Format setup functions */
115 -static int find_mbus_depth_by_code(u32 code)
116 -{
117 -       const struct unicam_fmt *fmt;
118 -       unsigned int k;
119 -
120 -       for (k = 0; k < ARRAY_SIZE(formats); k++) {
121 -               fmt = &formats[k];
122 -               if (fmt->code == code)
123 -                       return fmt->depth;
124 -       }
125 -
126 -       return 0;
127 -}
128 -
129  static const struct unicam_fmt *find_format_by_code(u32 code)
130  {
131         unsigned int k;
132 @@ -470,7 +470,8 @@ static const struct unicam_fmt *find_for
133         unsigned int k;
134  
135         for (k = 0; k < ARRAY_SIZE(formats); k++) {
136 -               if (formats[k].fourcc == pixelformat)
137 +               if (formats[k].fourcc == pixelformat ||
138 +                   formats[k].repacked_fourcc == pixelformat)
139                         return &formats[k];
140         }
141  
142 @@ -478,9 +479,14 @@ static const struct unicam_fmt *find_for
143  }
144  
145  static inline unsigned int bytes_per_line(u32 width,
146 -                                         const struct unicam_fmt *fmt)
147 +                                         const struct unicam_fmt *fmt,
148 +                                         u32 v4l2_fourcc)
149  {
150 -       return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
151 +       if (v4l2_fourcc == fmt->repacked_fourcc)
152 +               /* Repacking always goes to 16bpp */
153 +               return ALIGN(width << 1, BPL_ALIGNMENT);
154 +       else
155 +               return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
156  }
157  
158  static int __subdev_get_format(struct unicam_device *dev,
159 @@ -538,7 +544,8 @@ static int unicam_calc_format_size_bpl(s
160                               &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0,
161                               0);
162  
163 -       min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt);
164 +       min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt,
165 +                                         f->fmt.pix.pixelformat);
166  
167         if (f->fmt.pix.bytesperline > min_bytesperline &&
168             f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
169 @@ -738,6 +745,13 @@ static int unicam_enum_fmt_vid_cap(struc
170                                 }
171                                 index++;
172                         }
173 +                       if (fmt->repacked_fourcc) {
174 +                               if (index == f->index) {
175 +                                       f->pixelformat = fmt->repacked_fourcc;
176 +                                       break;
177 +                               }
178 +                               index++;
179 +                       }
180                 }
181         }
182  
183 @@ -858,7 +872,10 @@ static int unicam_try_fmt_vid_cap(struct
184                         }
185                 }
186  
187 -               f->fmt.pix.pixelformat = fmt->fourcc;
188 +               if (fmt->fourcc)
189 +                       f->fmt.pix.pixelformat = fmt->fourcc;
190 +               else
191 +                       f->fmt.pix.pixelformat = fmt->repacked_fourcc;
192         }
193  
194         return unicam_calc_format_size_bpl(dev, fmt, f);
195 @@ -998,16 +1015,14 @@ static void unicam_wr_dma_config(struct
196  
197  static void unicam_set_packing_config(struct unicam_device *dev)
198  {
199 -       int mbus_depth = find_mbus_depth_by_code(dev->fmt->code);
200 -       int v4l2_depth = dev->fmt->depth;
201         int pack, unpack;
202         u32 val;
203  
204 -       if (mbus_depth == v4l2_depth) {
205 +       if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) {
206                 unpack = UNICAM_PUM_NONE;
207                 pack = UNICAM_PPM_NONE;
208         } else {
209 -               switch (mbus_depth) {
210 +               switch (dev->fmt->depth) {
211                 case 8:
212                         unpack = UNICAM_PUM_UNPACK8;
213                         break;
214 @@ -1028,26 +1043,8 @@ static void unicam_set_packing_config(st
215                         break;
216                 }
217  
218 -               switch (v4l2_depth) {
219 -               case 8:
220 -                       pack = UNICAM_PPM_PACK8;
221 -                       break;
222 -               case 10:
223 -                       pack = UNICAM_PPM_PACK10;
224 -                       break;
225 -               case 12:
226 -                       pack = UNICAM_PPM_PACK12;
227 -                       break;
228 -               case 14:
229 -                       pack = UNICAM_PPM_PACK14;
230 -                       break;
231 -               case 16:
232 -                       pack = UNICAM_PPM_PACK16;
233 -                       break;
234 -               default:
235 -                       pack = UNICAM_PPM_NONE;
236 -                       break;
237 -               }
238 +               /* Repacking is always to 16bpp */
239 +               pack = UNICAM_PPM_PACK16;
240         }
241  
242         val = 0;
243 @@ -1893,7 +1890,10 @@ static int unicam_probe_complete(struct
244         }
245  
246         unicam->fmt = fmt;
247 -       unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
248 +       if (fmt->fourcc)
249 +               unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
250 +       else
251 +               unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
252  
253         /* Read current subdev format */
254         unicam_reset_format(unicam);