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/soc_mediabus.h> 17 18static 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 388int 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} 417EXPORT_SYMBOL(soc_mbus_samples_per_pixel); 418 419s32 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} 440EXPORT_SYMBOL(soc_mbus_bytes_per_line); 441 442s32 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} 458EXPORT_SYMBOL(soc_mbus_image_size); 459 460const 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} 473EXPORT_SYMBOL(soc_mbus_find_fmtdesc); 474 475const 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} 480EXPORT_SYMBOL(soc_mbus_get_fmtdesc); 481 482unsigned 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 case V4L2_MBUS_BT656: 498 pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | 499 V4L2_MBUS_PCLK_SAMPLE_FALLING); 500 data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | 501 V4L2_MBUS_DATA_ACTIVE_LOW); 502 mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); 503 return (!hsync || !vsync || !pclk || !data || !mode) ? 504 0 : common_flags; 505 case V4L2_MBUS_CSI2: 506 mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; 507 mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | 508 V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); 509 return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; 510 } 511 return 0; 512} 513EXPORT_SYMBOL(soc_mbus_config_compatible); 514 515static int __init soc_mbus_init(void) 516{ 517 return 0; 518} 519 520static void __exit soc_mbus_exit(void) 521{ 522} 523 524module_init(soc_mbus_init); 525module_exit(soc_mbus_exit); 526 527MODULE_DESCRIPTION("soc-camera media bus interface"); 528MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 529MODULE_LICENSE("GPL v2"); 530