1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * vimc-common.c Virtual Media Controller Driver 4 * 5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> 6 */ 7 8 #include <linux/init.h> 9 #include <linux/module.h> 10 11 #include <media/v4l2-ctrls.h> 12 13 #include "vimc-common.h" 14 15 /* 16 * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code 17 * in the scaler) 18 */ 19 static const struct vimc_pix_map vimc_pix_map_list[] = { 20 /* TODO: add all missing formats */ 21 22 /* RGB formats */ 23 { 24 .code = { 25 MEDIA_BUS_FMT_BGR888_1X24, 26 MEDIA_BUS_FMT_BGR888_3X8 27 }, 28 .pixelformat = V4L2_PIX_FMT_BGR24, 29 .bpp = 3, 30 .bayer = false, 31 }, 32 { 33 .code = { 34 MEDIA_BUS_FMT_RGB888_1X24, 35 MEDIA_BUS_FMT_RGB888_2X12_BE, 36 MEDIA_BUS_FMT_RGB888_2X12_LE, 37 MEDIA_BUS_FMT_RGB888_3X8, 38 MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 39 MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 40 MEDIA_BUS_FMT_RGB888_1X32_PADHI, 41 MEDIA_BUS_FMT_GBR888_1X24 42 }, 43 .pixelformat = V4L2_PIX_FMT_RGB24, 44 .bpp = 3, 45 .bayer = false, 46 }, 47 { 48 .code = { MEDIA_BUS_FMT_ARGB8888_1X32 }, 49 .pixelformat = V4L2_PIX_FMT_ARGB32, 50 .bpp = 4, 51 .bayer = false, 52 }, 53 54 /* Bayer formats */ 55 { 56 .code = { MEDIA_BUS_FMT_SBGGR8_1X8 }, 57 .pixelformat = V4L2_PIX_FMT_SBGGR8, 58 .bpp = 1, 59 .bayer = true, 60 }, 61 { 62 .code = { MEDIA_BUS_FMT_SGBRG8_1X8 }, 63 .pixelformat = V4L2_PIX_FMT_SGBRG8, 64 .bpp = 1, 65 .bayer = true, 66 }, 67 { 68 .code = { MEDIA_BUS_FMT_SGRBG8_1X8 }, 69 .pixelformat = V4L2_PIX_FMT_SGRBG8, 70 .bpp = 1, 71 .bayer = true, 72 }, 73 { 74 .code = { MEDIA_BUS_FMT_SRGGB8_1X8 }, 75 .pixelformat = V4L2_PIX_FMT_SRGGB8, 76 .bpp = 1, 77 .bayer = true, 78 }, 79 { 80 .code = { MEDIA_BUS_FMT_SBGGR10_1X10 }, 81 .pixelformat = V4L2_PIX_FMT_SBGGR10, 82 .bpp = 2, 83 .bayer = true, 84 }, 85 { 86 .code = { MEDIA_BUS_FMT_SGBRG10_1X10 }, 87 .pixelformat = V4L2_PIX_FMT_SGBRG10, 88 .bpp = 2, 89 .bayer = true, 90 }, 91 { 92 .code = { MEDIA_BUS_FMT_SGRBG10_1X10 }, 93 .pixelformat = V4L2_PIX_FMT_SGRBG10, 94 .bpp = 2, 95 .bayer = true, 96 }, 97 { 98 .code = { MEDIA_BUS_FMT_SRGGB10_1X10 }, 99 .pixelformat = V4L2_PIX_FMT_SRGGB10, 100 .bpp = 2, 101 .bayer = true, 102 }, 103 104 /* 10bit raw bayer a-law compressed to 8 bits */ 105 { 106 .code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 }, 107 .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, 108 .bpp = 1, 109 .bayer = true, 110 }, 111 { 112 .code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 }, 113 .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, 114 .bpp = 1, 115 .bayer = true, 116 }, 117 { 118 .code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 }, 119 .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, 120 .bpp = 1, 121 .bayer = true, 122 }, 123 { 124 .code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 }, 125 .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, 126 .bpp = 1, 127 .bayer = true, 128 }, 129 130 /* 10bit raw bayer DPCM compressed to 8 bits */ 131 { 132 .code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 }, 133 .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, 134 .bpp = 1, 135 .bayer = true, 136 }, 137 { 138 .code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 }, 139 .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, 140 .bpp = 1, 141 .bayer = true, 142 }, 143 { 144 .code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 }, 145 .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, 146 .bpp = 1, 147 .bayer = true, 148 }, 149 { 150 .code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 }, 151 .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, 152 .bpp = 1, 153 .bayer = true, 154 }, 155 { 156 .code = { MEDIA_BUS_FMT_SBGGR12_1X12 }, 157 .pixelformat = V4L2_PIX_FMT_SBGGR12, 158 .bpp = 2, 159 .bayer = true, 160 }, 161 { 162 .code = { MEDIA_BUS_FMT_SGBRG12_1X12 }, 163 .pixelformat = V4L2_PIX_FMT_SGBRG12, 164 .bpp = 2, 165 .bayer = true, 166 }, 167 { 168 .code = { MEDIA_BUS_FMT_SGRBG12_1X12 }, 169 .pixelformat = V4L2_PIX_FMT_SGRBG12, 170 .bpp = 2, 171 .bayer = true, 172 }, 173 { 174 .code = { MEDIA_BUS_FMT_SRGGB12_1X12 }, 175 .pixelformat = V4L2_PIX_FMT_SRGGB12, 176 .bpp = 2, 177 .bayer = true, 178 }, 179 }; 180 181 bool vimc_is_source(struct media_entity *ent) 182 { 183 unsigned int i; 184 185 for (i = 0; i < ent->num_pads; i++) 186 if (ent->pads[i].flags & MEDIA_PAD_FL_SINK) 187 return false; 188 return true; 189 } 190 191 const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) 192 { 193 if (i >= ARRAY_SIZE(vimc_pix_map_list)) 194 return NULL; 195 196 return &vimc_pix_map_list[i]; 197 } 198 199 u32 vimc_mbus_code_by_index(unsigned int index) 200 { 201 unsigned int i, j; 202 203 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { 204 for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) { 205 if (!vimc_pix_map_list[i].code[j]) 206 break; 207 208 if (!index) 209 return vimc_pix_map_list[i].code[j]; 210 index--; 211 } 212 } 213 return 0; 214 } 215 216 const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) 217 { 218 unsigned int i, j; 219 220 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { 221 for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) { 222 if (vimc_pix_map_list[i].code[j] == code) 223 return &vimc_pix_map_list[i]; 224 } 225 } 226 return NULL; 227 } 228 229 const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) 230 { 231 unsigned int i; 232 233 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { 234 if (vimc_pix_map_list[i].pixelformat == pixelformat) 235 return &vimc_pix_map_list[i]; 236 } 237 return NULL; 238 } 239 240 static int vimc_get_pix_format(struct media_pad *pad, 241 struct v4l2_pix_format *fmt) 242 { 243 if (is_media_entity_v4l2_subdev(pad->entity)) { 244 struct v4l2_subdev *sd = 245 media_entity_to_v4l2_subdev(pad->entity); 246 struct v4l2_subdev_format sd_fmt = { 247 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 248 .pad = pad->index, 249 }; 250 const struct vimc_pix_map *pix_map; 251 int ret; 252 253 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); 254 if (ret) 255 return ret; 256 257 v4l2_fill_pix_format(fmt, &sd_fmt.format); 258 pix_map = vimc_pix_map_by_code(sd_fmt.format.code); 259 fmt->pixelformat = pix_map->pixelformat; 260 } else if (is_media_entity_v4l2_video_device(pad->entity)) { 261 struct video_device *vdev = container_of(pad->entity, 262 struct video_device, 263 entity); 264 struct vimc_ent_device *ved = video_get_drvdata(vdev); 265 266 if (!ved->vdev_get_format) 267 return -ENOIOCTLCMD; 268 269 ved->vdev_get_format(ved, fmt); 270 } else { 271 return -EINVAL; 272 } 273 274 return 0; 275 } 276 277 int vimc_vdev_link_validate(struct media_link *link) 278 { 279 struct v4l2_pix_format source_fmt, sink_fmt; 280 int ret; 281 282 ret = vimc_get_pix_format(link->source, &source_fmt); 283 if (ret) 284 return ret; 285 286 ret = vimc_get_pix_format(link->sink, &sink_fmt); 287 if (ret) 288 return ret; 289 290 pr_info("vimc link validate: " 291 "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " 292 "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", 293 /* src */ 294 link->source->entity->name, 295 source_fmt.width, source_fmt.height, 296 source_fmt.pixelformat, source_fmt.colorspace, 297 source_fmt.quantization, source_fmt.xfer_func, 298 source_fmt.ycbcr_enc, 299 /* sink */ 300 link->sink->entity->name, 301 sink_fmt.width, sink_fmt.height, 302 sink_fmt.pixelformat, sink_fmt.colorspace, 303 sink_fmt.quantization, sink_fmt.xfer_func, 304 sink_fmt.ycbcr_enc); 305 306 /* The width, height and pixelformat must match. */ 307 if (source_fmt.width != sink_fmt.width || 308 source_fmt.height != sink_fmt.height || 309 source_fmt.pixelformat != sink_fmt.pixelformat) 310 return -EPIPE; 311 312 /* 313 * The field order must match, or the sink field order must be NONE 314 * to support interlaced hardware connected to bridges that support 315 * progressive formats only. 316 */ 317 if (source_fmt.field != sink_fmt.field && 318 sink_fmt.field != V4L2_FIELD_NONE) 319 return -EPIPE; 320 321 /* 322 * If colorspace is DEFAULT, then assume all the colorimetry is also 323 * DEFAULT, return 0 to skip comparing the other colorimetry parameters 324 */ 325 if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT || 326 sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT) 327 return 0; 328 329 /* Colorspace must match. */ 330 if (source_fmt.colorspace != sink_fmt.colorspace) 331 return -EPIPE; 332 333 /* Colorimetry must match if they are not set to DEFAULT */ 334 if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && 335 sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && 336 source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc) 337 return -EPIPE; 338 339 if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && 340 sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && 341 source_fmt.quantization != sink_fmt.quantization) 342 return -EPIPE; 343 344 if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && 345 sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && 346 source_fmt.xfer_func != sink_fmt.xfer_func) 347 return -EPIPE; 348 349 return 0; 350 } 351 352 static const struct media_entity_operations vimc_ent_sd_mops = { 353 .link_validate = v4l2_subdev_link_validate, 354 }; 355 356 int vimc_ent_sd_register(struct vimc_ent_device *ved, 357 struct v4l2_subdev *sd, 358 struct v4l2_device *v4l2_dev, 359 const char *const name, 360 u32 function, 361 u16 num_pads, 362 struct media_pad *pads, 363 const struct v4l2_subdev_internal_ops *int_ops, 364 const struct v4l2_subdev_ops *sd_ops) 365 { 366 int ret; 367 368 /* Fill the vimc_ent_device struct */ 369 ved->ent = &sd->entity; 370 371 /* Initialize the subdev */ 372 v4l2_subdev_init(sd, sd_ops); 373 sd->internal_ops = int_ops; 374 sd->entity.function = function; 375 sd->entity.ops = &vimc_ent_sd_mops; 376 sd->owner = THIS_MODULE; 377 strscpy(sd->name, name, sizeof(sd->name)); 378 v4l2_set_subdevdata(sd, ved); 379 380 /* Expose this subdev to user space */ 381 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 382 if (sd->ctrl_handler) 383 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; 384 385 /* Initialize the media entity */ 386 ret = media_entity_pads_init(&sd->entity, num_pads, pads); 387 if (ret) 388 return ret; 389 390 /* 391 * Finalize the subdev initialization if it supports active states. Use 392 * the control handler lock as the state lock if available. 393 */ 394 if (int_ops && int_ops->init_state) { 395 if (sd->ctrl_handler) 396 sd->state_lock = sd->ctrl_handler->lock; 397 398 ret = v4l2_subdev_init_finalize(sd); 399 if (ret) { 400 dev_err(v4l2_dev->dev, 401 "%s: subdev initialization failed (err=%d)\n", 402 name, ret); 403 goto err_clean_m_ent; 404 } 405 } 406 407 /* Register the subdev with the v4l2 and the media framework */ 408 ret = v4l2_device_register_subdev(v4l2_dev, sd); 409 if (ret) { 410 dev_err(v4l2_dev->dev, 411 "%s: subdev register failed (err=%d)\n", 412 name, ret); 413 goto err_clean_sd; 414 } 415 416 return 0; 417 418 err_clean_sd: 419 v4l2_subdev_cleanup(sd); 420 err_clean_m_ent: 421 media_entity_cleanup(&sd->entity); 422 return ret; 423 } 424