1 /*
2 * soc-camera media bus helper routines
3 *
4 * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13
14 #include <media/v4l2-device.h>
15 #include <media/v4l2-mediabus.h>
16 #include <media/drv-intf/soc_mediabus.h>
17
18 static const struct soc_mbus_lookup mbus_fmt[] = {
19 {
20 .code = MEDIA_BUS_FMT_YUYV8_2X8,
21 .fmt = {
22 .fourcc = V4L2_PIX_FMT_YUYV,
23 .name = "YUYV",
24 .bits_per_sample = 8,
25 .packing = SOC_MBUS_PACKING_2X8_PADHI,
26 .order = SOC_MBUS_ORDER_LE,
27 .layout = SOC_MBUS_LAYOUT_PACKED,
28 },
29 }, {
30 .code = MEDIA_BUS_FMT_YVYU8_2X8,
31 .fmt = {
32 .fourcc = V4L2_PIX_FMT_YVYU,
33 .name = "YVYU",
34 .bits_per_sample = 8,
35 .packing = SOC_MBUS_PACKING_2X8_PADHI,
36 .order = SOC_MBUS_ORDER_LE,
37 .layout = SOC_MBUS_LAYOUT_PACKED,
38 },
39 }, {
40 .code = MEDIA_BUS_FMT_UYVY8_2X8,
41 .fmt = {
42 .fourcc = V4L2_PIX_FMT_UYVY,
43 .name = "UYVY",
44 .bits_per_sample = 8,
45 .packing = SOC_MBUS_PACKING_2X8_PADHI,
46 .order = SOC_MBUS_ORDER_LE,
47 .layout = SOC_MBUS_LAYOUT_PACKED,
48 },
49 }, {
50 .code = MEDIA_BUS_FMT_VYUY8_2X8,
51 .fmt = {
52 .fourcc = V4L2_PIX_FMT_VYUY,
53 .name = "VYUY",
54 .bits_per_sample = 8,
55 .packing = SOC_MBUS_PACKING_2X8_PADHI,
56 .order = SOC_MBUS_ORDER_LE,
57 .layout = SOC_MBUS_LAYOUT_PACKED,
58 },
59 }, {
60 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
61 .fmt = {
62 .fourcc = V4L2_PIX_FMT_RGB555,
63 .name = "RGB555",
64 .bits_per_sample = 8,
65 .packing = SOC_MBUS_PACKING_2X8_PADHI,
66 .order = SOC_MBUS_ORDER_LE,
67 .layout = SOC_MBUS_LAYOUT_PACKED,
68 },
69 }, {
70 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
71 .fmt = {
72 .fourcc = V4L2_PIX_FMT_RGB555X,
73 .name = "RGB555X",
74 .bits_per_sample = 8,
75 .packing = SOC_MBUS_PACKING_2X8_PADHI,
76 .order = SOC_MBUS_ORDER_BE,
77 .layout = SOC_MBUS_LAYOUT_PACKED,
78 },
79 }, {
80 .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
81 .fmt = {
82 .fourcc = V4L2_PIX_FMT_RGB565,
83 .name = "RGB565",
84 .bits_per_sample = 8,
85 .packing = SOC_MBUS_PACKING_2X8_PADHI,
86 .order = SOC_MBUS_ORDER_LE,
87 .layout = SOC_MBUS_LAYOUT_PACKED,
88 },
89 }, {
90 .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
91 .fmt = {
92 .fourcc = V4L2_PIX_FMT_RGB565X,
93 .name = "RGB565X",
94 .bits_per_sample = 8,
95 .packing = SOC_MBUS_PACKING_2X8_PADHI,
96 .order = SOC_MBUS_ORDER_BE,
97 .layout = SOC_MBUS_LAYOUT_PACKED,
98 },
99 }, {
100 .code = MEDIA_BUS_FMT_RGB666_1X18,
101 .fmt = {
102 .fourcc = V4L2_PIX_FMT_RGB32,
103 .name = "RGB666/32bpp",
104 .bits_per_sample = 18,
105 .packing = SOC_MBUS_PACKING_EXTEND32,
106 .order = SOC_MBUS_ORDER_LE,
107 },
108 }, {
109 .code = MEDIA_BUS_FMT_RGB888_1X24,
110 .fmt = {
111 .fourcc = V4L2_PIX_FMT_RGB32,
112 .name = "RGB888/32bpp",
113 .bits_per_sample = 24,
114 .packing = SOC_MBUS_PACKING_EXTEND32,
115 .order = SOC_MBUS_ORDER_LE,
116 },
117 }, {
118 .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
119 .fmt = {
120 .fourcc = V4L2_PIX_FMT_RGB32,
121 .name = "RGB888/32bpp",
122 .bits_per_sample = 12,
123 .packing = SOC_MBUS_PACKING_EXTEND32,
124 .order = SOC_MBUS_ORDER_BE,
125 },
126 }, {
127 .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
128 .fmt = {
129 .fourcc = V4L2_PIX_FMT_RGB32,
130 .name = "RGB888/32bpp",
131 .bits_per_sample = 12,
132 .packing = SOC_MBUS_PACKING_EXTEND32,
133 .order = SOC_MBUS_ORDER_LE,
134 },
135 }, {
136 .code = MEDIA_BUS_FMT_SBGGR8_1X8,
137 .fmt = {
138 .fourcc = V4L2_PIX_FMT_SBGGR8,
139 .name = "Bayer 8 BGGR",
140 .bits_per_sample = 8,
141 .packing = SOC_MBUS_PACKING_NONE,
142 .order = SOC_MBUS_ORDER_LE,
143 .layout = SOC_MBUS_LAYOUT_PACKED,
144 },
145 }, {
146 .code = MEDIA_BUS_FMT_SBGGR10_1X10,
147 .fmt = {
148 .fourcc = V4L2_PIX_FMT_SBGGR10,
149 .name = "Bayer 10 BGGR",
150 .bits_per_sample = 10,
151 .packing = SOC_MBUS_PACKING_EXTEND16,
152 .order = SOC_MBUS_ORDER_LE,
153 .layout = SOC_MBUS_LAYOUT_PACKED,
154 },
155 }, {
156 .code = MEDIA_BUS_FMT_Y8_1X8,
157 .fmt = {
158 .fourcc = V4L2_PIX_FMT_GREY,
159 .name = "Grey",
160 .bits_per_sample = 8,
161 .packing = SOC_MBUS_PACKING_NONE,
162 .order = SOC_MBUS_ORDER_LE,
163 .layout = SOC_MBUS_LAYOUT_PACKED,
164 },
165 }, {
166 .code = MEDIA_BUS_FMT_Y10_1X10,
167 .fmt = {
168 .fourcc = V4L2_PIX_FMT_Y10,
169 .name = "Grey 10bit",
170 .bits_per_sample = 10,
171 .packing = SOC_MBUS_PACKING_EXTEND16,
172 .order = SOC_MBUS_ORDER_LE,
173 .layout = SOC_MBUS_LAYOUT_PACKED,
174 },
175 }, {
176 .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
177 .fmt = {
178 .fourcc = V4L2_PIX_FMT_SBGGR10,
179 .name = "Bayer 10 BGGR",
180 .bits_per_sample = 8,
181 .packing = SOC_MBUS_PACKING_2X8_PADHI,
182 .order = SOC_MBUS_ORDER_LE,
183 .layout = SOC_MBUS_LAYOUT_PACKED,
184 },
185 }, {
186 .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE,
187 .fmt = {
188 .fourcc = V4L2_PIX_FMT_SBGGR10,
189 .name = "Bayer 10 BGGR",
190 .bits_per_sample = 8,
191 .packing = SOC_MBUS_PACKING_2X8_PADLO,
192 .order = SOC_MBUS_ORDER_LE,
193 .layout = SOC_MBUS_LAYOUT_PACKED,
194 },
195 }, {
196 .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
197 .fmt = {
198 .fourcc = V4L2_PIX_FMT_SBGGR10,
199 .name = "Bayer 10 BGGR",
200 .bits_per_sample = 8,
201 .packing = SOC_MBUS_PACKING_2X8_PADHI,
202 .order = SOC_MBUS_ORDER_BE,
203 .layout = SOC_MBUS_LAYOUT_PACKED,
204 },
205 }, {
206 .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE,
207 .fmt = {
208 .fourcc = V4L2_PIX_FMT_SBGGR10,
209 .name = "Bayer 10 BGGR",
210 .bits_per_sample = 8,
211 .packing = SOC_MBUS_PACKING_2X8_PADLO,
212 .order = SOC_MBUS_ORDER_BE,
213 .layout = SOC_MBUS_LAYOUT_PACKED,
214 },
215 }, {
216 .code = MEDIA_BUS_FMT_JPEG_1X8,
217 .fmt = {
218 .fourcc = V4L2_PIX_FMT_JPEG,
219 .name = "JPEG",
220 .bits_per_sample = 8,
221 .packing = SOC_MBUS_PACKING_VARIABLE,
222 .order = SOC_MBUS_ORDER_LE,
223 .layout = SOC_MBUS_LAYOUT_PACKED,
224 },
225 }, {
226 .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE,
227 .fmt = {
228 .fourcc = V4L2_PIX_FMT_RGB444,
229 .name = "RGB444",
230 .bits_per_sample = 8,
231 .packing = SOC_MBUS_PACKING_2X8_PADHI,
232 .order = SOC_MBUS_ORDER_BE,
233 .layout = SOC_MBUS_LAYOUT_PACKED,
234 },
235 }, {
236 .code = MEDIA_BUS_FMT_YUYV8_1_5X8,
237 .fmt = {
238 .fourcc = V4L2_PIX_FMT_YUV420,
239 .name = "YUYV 4:2:0",
240 .bits_per_sample = 8,
241 .packing = SOC_MBUS_PACKING_1_5X8,
242 .order = SOC_MBUS_ORDER_LE,
243 .layout = SOC_MBUS_LAYOUT_PACKED,
244 },
245 }, {
246 .code = MEDIA_BUS_FMT_YVYU8_1_5X8,
247 .fmt = {
248 .fourcc = V4L2_PIX_FMT_YVU420,
249 .name = "YVYU 4:2:0",
250 .bits_per_sample = 8,
251 .packing = SOC_MBUS_PACKING_1_5X8,
252 .order = SOC_MBUS_ORDER_LE,
253 .layout = SOC_MBUS_LAYOUT_PACKED,
254 },
255 }, {
256 .code = MEDIA_BUS_FMT_UYVY8_1X16,
257 .fmt = {
258 .fourcc = V4L2_PIX_FMT_UYVY,
259 .name = "UYVY 16bit",
260 .bits_per_sample = 16,
261 .packing = SOC_MBUS_PACKING_EXTEND16,
262 .order = SOC_MBUS_ORDER_LE,
263 .layout = SOC_MBUS_LAYOUT_PACKED,
264 },
265 }, {
266 .code = MEDIA_BUS_FMT_VYUY8_1X16,
267 .fmt = {
268 .fourcc = V4L2_PIX_FMT_VYUY,
269 .name = "VYUY 16bit",
270 .bits_per_sample = 16,
271 .packing = SOC_MBUS_PACKING_EXTEND16,
272 .order = SOC_MBUS_ORDER_LE,
273 .layout = SOC_MBUS_LAYOUT_PACKED,
274 },
275 }, {
276 .code = MEDIA_BUS_FMT_YUYV8_1X16,
277 .fmt = {
278 .fourcc = V4L2_PIX_FMT_YUYV,
279 .name = "YUYV 16bit",
280 .bits_per_sample = 16,
281 .packing = SOC_MBUS_PACKING_EXTEND16,
282 .order = SOC_MBUS_ORDER_LE,
283 .layout = SOC_MBUS_LAYOUT_PACKED,
284 },
285 }, {
286 .code = MEDIA_BUS_FMT_YVYU8_1X16,
287 .fmt = {
288 .fourcc = V4L2_PIX_FMT_YVYU,
289 .name = "YVYU 16bit",
290 .bits_per_sample = 16,
291 .packing = SOC_MBUS_PACKING_EXTEND16,
292 .order = SOC_MBUS_ORDER_LE,
293 .layout = SOC_MBUS_LAYOUT_PACKED,
294 },
295 }, {
296 .code = MEDIA_BUS_FMT_SGRBG8_1X8,
297 .fmt = {
298 .fourcc = V4L2_PIX_FMT_SGRBG8,
299 .name = "Bayer 8 GRBG",
300 .bits_per_sample = 8,
301 .packing = SOC_MBUS_PACKING_NONE,
302 .order = SOC_MBUS_ORDER_LE,
303 .layout = SOC_MBUS_LAYOUT_PACKED,
304 },
305 }, {
306 .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
307 .fmt = {
308 .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8,
309 .name = "Bayer 10 BGGR DPCM 8",
310 .bits_per_sample = 8,
311 .packing = SOC_MBUS_PACKING_NONE,
312 .order = SOC_MBUS_ORDER_LE,
313 .layout = SOC_MBUS_LAYOUT_PACKED,
314 },
315 }, {
316 .code = MEDIA_BUS_FMT_SGBRG10_1X10,
317 .fmt = {
318 .fourcc = V4L2_PIX_FMT_SGBRG10,
319 .name = "Bayer 10 GBRG",
320 .bits_per_sample = 10,
321 .packing = SOC_MBUS_PACKING_EXTEND16,
322 .order = SOC_MBUS_ORDER_LE,
323 .layout = SOC_MBUS_LAYOUT_PACKED,
324 },
325 }, {
326 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
327 .fmt = {
328 .fourcc = V4L2_PIX_FMT_SGRBG10,
329 .name = "Bayer 10 GRBG",
330 .bits_per_sample = 10,
331 .packing = SOC_MBUS_PACKING_EXTEND16,
332 .order = SOC_MBUS_ORDER_LE,
333 .layout = SOC_MBUS_LAYOUT_PACKED,
334 },
335 }, {
336 .code = MEDIA_BUS_FMT_SRGGB10_1X10,
337 .fmt = {
338 .fourcc = V4L2_PIX_FMT_SRGGB10,
339 .name = "Bayer 10 RGGB",
340 .bits_per_sample = 10,
341 .packing = SOC_MBUS_PACKING_EXTEND16,
342 .order = SOC_MBUS_ORDER_LE,
343 .layout = SOC_MBUS_LAYOUT_PACKED,
344 },
345 }, {
346 .code = MEDIA_BUS_FMT_SBGGR12_1X12,
347 .fmt = {
348 .fourcc = V4L2_PIX_FMT_SBGGR12,
349 .name = "Bayer 12 BGGR",
350 .bits_per_sample = 12,
351 .packing = SOC_MBUS_PACKING_EXTEND16,
352 .order = SOC_MBUS_ORDER_LE,
353 .layout = SOC_MBUS_LAYOUT_PACKED,
354 },
355 }, {
356 .code = MEDIA_BUS_FMT_SGBRG12_1X12,
357 .fmt = {
358 .fourcc = V4L2_PIX_FMT_SGBRG12,
359 .name = "Bayer 12 GBRG",
360 .bits_per_sample = 12,
361 .packing = SOC_MBUS_PACKING_EXTEND16,
362 .order = SOC_MBUS_ORDER_LE,
363 .layout = SOC_MBUS_LAYOUT_PACKED,
364 },
365 }, {
366 .code = MEDIA_BUS_FMT_SGRBG12_1X12,
367 .fmt = {
368 .fourcc = V4L2_PIX_FMT_SGRBG12,
369 .name = "Bayer 12 GRBG",
370 .bits_per_sample = 12,
371 .packing = SOC_MBUS_PACKING_EXTEND16,
372 .order = SOC_MBUS_ORDER_LE,
373 .layout = SOC_MBUS_LAYOUT_PACKED,
374 },
375 }, {
376 .code = MEDIA_BUS_FMT_SRGGB12_1X12,
377 .fmt = {
378 .fourcc = V4L2_PIX_FMT_SRGGB12,
379 .name = "Bayer 12 RGGB",
380 .bits_per_sample = 12,
381 .packing = SOC_MBUS_PACKING_EXTEND16,
382 .order = SOC_MBUS_ORDER_LE,
383 .layout = SOC_MBUS_LAYOUT_PACKED,
384 },
385 },
386 };
387
soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt * mf,unsigned int * numerator,unsigned int * denominator)388 int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
389 unsigned int *numerator, unsigned int *denominator)
390 {
391 switch (mf->packing) {
392 case SOC_MBUS_PACKING_NONE:
393 case SOC_MBUS_PACKING_EXTEND16:
394 *numerator = 1;
395 *denominator = 1;
396 return 0;
397 case SOC_MBUS_PACKING_EXTEND32:
398 *numerator = 1;
399 *denominator = 1;
400 return 0;
401 case SOC_MBUS_PACKING_2X8_PADHI:
402 case SOC_MBUS_PACKING_2X8_PADLO:
403 *numerator = 2;
404 *denominator = 1;
405 return 0;
406 case SOC_MBUS_PACKING_1_5X8:
407 *numerator = 3;
408 *denominator = 2;
409 return 0;
410 case SOC_MBUS_PACKING_VARIABLE:
411 *numerator = 0;
412 *denominator = 1;
413 return 0;
414 }
415 return -EINVAL;
416 }
417 EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
418
soc_mbus_bytes_per_line(u32 width,const struct soc_mbus_pixelfmt * mf)419 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
420 {
421 if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
422 return width * mf->bits_per_sample / 8;
423
424 switch (mf->packing) {
425 case SOC_MBUS_PACKING_NONE:
426 return width * mf->bits_per_sample / 8;
427 case SOC_MBUS_PACKING_2X8_PADHI:
428 case SOC_MBUS_PACKING_2X8_PADLO:
429 case SOC_MBUS_PACKING_EXTEND16:
430 return width * 2;
431 case SOC_MBUS_PACKING_1_5X8:
432 return width * 3 / 2;
433 case SOC_MBUS_PACKING_VARIABLE:
434 return 0;
435 case SOC_MBUS_PACKING_EXTEND32:
436 return width * 4;
437 }
438 return -EINVAL;
439 }
440 EXPORT_SYMBOL(soc_mbus_bytes_per_line);
441
soc_mbus_image_size(const struct soc_mbus_pixelfmt * mf,u32 bytes_per_line,u32 height)442 s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
443 u32 bytes_per_line, u32 height)
444 {
445 if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
446 return bytes_per_line * height;
447
448 switch (mf->packing) {
449 case SOC_MBUS_PACKING_2X8_PADHI:
450 case SOC_MBUS_PACKING_2X8_PADLO:
451 return bytes_per_line * height * 2;
452 case SOC_MBUS_PACKING_1_5X8:
453 return bytes_per_line * height * 3 / 2;
454 default:
455 return -EINVAL;
456 }
457 }
458 EXPORT_SYMBOL(soc_mbus_image_size);
459
soc_mbus_find_fmtdesc(u32 code,const struct soc_mbus_lookup * lookup,int n)460 const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
461 u32 code,
462 const struct soc_mbus_lookup *lookup,
463 int n)
464 {
465 int i;
466
467 for (i = 0; i < n; i++)
468 if (lookup[i].code == code)
469 return &lookup[i].fmt;
470
471 return NULL;
472 }
473 EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
474
soc_mbus_get_fmtdesc(u32 code)475 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
476 u32 code)
477 {
478 return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
479 }
480 EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
481
soc_mbus_config_compatible(const struct v4l2_mbus_config * cfg,unsigned int flags)482 unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
483 unsigned int flags)
484 {
485 unsigned long common_flags;
486 bool hsync = true, vsync = true, pclk, data, mode;
487 bool mipi_lanes, mipi_clock;
488
489 common_flags = cfg->flags & flags;
490
491 switch (cfg->type) {
492 case V4L2_MBUS_PARALLEL:
493 hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
494 V4L2_MBUS_HSYNC_ACTIVE_LOW);
495 vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
496 V4L2_MBUS_VSYNC_ACTIVE_LOW);
497 /* fall through */
498 case V4L2_MBUS_BT656:
499 pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
500 V4L2_MBUS_PCLK_SAMPLE_FALLING);
501 data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
502 V4L2_MBUS_DATA_ACTIVE_LOW);
503 mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
504 return (!hsync || !vsync || !pclk || !data || !mode) ?
505 0 : common_flags;
506 case V4L2_MBUS_CSI2:
507 mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
508 mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
509 V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
510 return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
511 default:
512 WARN_ON(1);
513 return -EINVAL;
514 }
515 return 0;
516 }
517 EXPORT_SYMBOL(soc_mbus_config_compatible);
518
soc_mbus_init(void)519 static int __init soc_mbus_init(void)
520 {
521 return 0;
522 }
523
soc_mbus_exit(void)524 static void __exit soc_mbus_exit(void)
525 {
526 }
527
528 module_init(soc_mbus_init);
529 module_exit(soc_mbus_exit);
530
531 MODULE_DESCRIPTION("soc-camera media bus interface");
532 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
533 MODULE_LICENSE("GPL v2");
534