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