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 const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) 186 { 187 unsigned int i; 188 189 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { 190 if (vimc_pix_map_list[i].code == code) 191 return &vimc_pix_map_list[i]; 192 } 193 return NULL; 194 } 195 196 const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) 197 { 198 unsigned int i; 199 200 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { 201 if (vimc_pix_map_list[i].pixelformat == pixelformat) 202 return &vimc_pix_map_list[i]; 203 } 204 return NULL; 205 } 206 207 static int vimc_get_pix_format(struct media_pad *pad, 208 struct v4l2_pix_format *fmt) 209 { 210 if (is_media_entity_v4l2_subdev(pad->entity)) { 211 struct v4l2_subdev *sd = 212 media_entity_to_v4l2_subdev(pad->entity); 213 struct v4l2_subdev_format sd_fmt; 214 const struct vimc_pix_map *pix_map; 215 int ret; 216 217 sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 218 sd_fmt.pad = pad->index; 219 220 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); 221 if (ret) 222 return ret; 223 224 v4l2_fill_pix_format(fmt, &sd_fmt.format); 225 pix_map = vimc_pix_map_by_code(sd_fmt.format.code); 226 fmt->pixelformat = pix_map->pixelformat; 227 } else if (is_media_entity_v4l2_video_device(pad->entity)) { 228 struct video_device *vdev = container_of(pad->entity, 229 struct video_device, 230 entity); 231 struct vimc_ent_device *ved = video_get_drvdata(vdev); 232 233 if (!ved->vdev_get_format) 234 return -ENOIOCTLCMD; 235 236 ved->vdev_get_format(ved, fmt); 237 } else { 238 return -EINVAL; 239 } 240 241 return 0; 242 } 243 244 int vimc_vdev_link_validate(struct media_link *link) 245 { 246 struct v4l2_pix_format source_fmt, sink_fmt; 247 int ret; 248 249 ret = vimc_get_pix_format(link->source, &source_fmt); 250 if (ret) 251 return ret; 252 253 ret = vimc_get_pix_format(link->sink, &sink_fmt); 254 if (ret) 255 return ret; 256 257 pr_info("vimc link validate: " 258 "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " 259 "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", 260 /* src */ 261 link->source->entity->name, 262 source_fmt.width, source_fmt.height, 263 source_fmt.pixelformat, source_fmt.colorspace, 264 source_fmt.quantization, source_fmt.xfer_func, 265 source_fmt.ycbcr_enc, 266 /* sink */ 267 link->sink->entity->name, 268 sink_fmt.width, sink_fmt.height, 269 sink_fmt.pixelformat, sink_fmt.colorspace, 270 sink_fmt.quantization, sink_fmt.xfer_func, 271 sink_fmt.ycbcr_enc); 272 273 /* The width, height and pixelformat must match. */ 274 if (source_fmt.width != sink_fmt.width || 275 source_fmt.height != sink_fmt.height || 276 source_fmt.pixelformat != sink_fmt.pixelformat) 277 return -EPIPE; 278 279 /* 280 * The field order must match, or the sink field order must be NONE 281 * to support interlaced hardware connected to bridges that support 282 * progressive formats only. 283 */ 284 if (source_fmt.field != sink_fmt.field && 285 sink_fmt.field != V4L2_FIELD_NONE) 286 return -EPIPE; 287 288 /* 289 * If colorspace is DEFAULT, then assume all the colorimetry is also 290 * DEFAULT, return 0 to skip comparing the other colorimetry parameters 291 */ 292 if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT || 293 sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT) 294 return 0; 295 296 /* Colorspace must match. */ 297 if (source_fmt.colorspace != sink_fmt.colorspace) 298 return -EPIPE; 299 300 /* Colorimetry must match if they are not set to DEFAULT */ 301 if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && 302 sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && 303 source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc) 304 return -EPIPE; 305 306 if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && 307 sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && 308 source_fmt.quantization != sink_fmt.quantization) 309 return -EPIPE; 310 311 if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && 312 sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && 313 source_fmt.xfer_func != sink_fmt.xfer_func) 314 return -EPIPE; 315 316 return 0; 317 } 318 319 static const struct media_entity_operations vimc_ent_sd_mops = { 320 .link_validate = v4l2_subdev_link_validate, 321 }; 322 323 int vimc_ent_sd_register(struct vimc_ent_device *ved, 324 struct v4l2_subdev *sd, 325 struct v4l2_device *v4l2_dev, 326 const char *const name, 327 u32 function, 328 u16 num_pads, 329 struct media_pad *pads, 330 const struct v4l2_subdev_ops *sd_ops) 331 { 332 int ret; 333 334 /* Fill the vimc_ent_device struct */ 335 ved->ent = &sd->entity; 336 337 /* Initialize the subdev */ 338 v4l2_subdev_init(sd, sd_ops); 339 sd->entity.function = function; 340 sd->entity.ops = &vimc_ent_sd_mops; 341 sd->owner = THIS_MODULE; 342 strscpy(sd->name, name, sizeof(sd->name)); 343 v4l2_set_subdevdata(sd, ved); 344 345 /* Expose this subdev to user space */ 346 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 347 if (sd->ctrl_handler) 348 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; 349 350 /* Initialize the media entity */ 351 ret = media_entity_pads_init(&sd->entity, num_pads, pads); 352 if (ret) 353 return ret; 354 355 /* Register the subdev with the v4l2 and the media framework */ 356 ret = v4l2_device_register_subdev(v4l2_dev, sd); 357 if (ret) { 358 dev_err(v4l2_dev->dev, 359 "%s: subdev register failed (err=%d)\n", 360 name, ret); 361 goto err_clean_m_ent; 362 } 363 364 return 0; 365 366 err_clean_m_ent: 367 media_entity_cleanup(&sd->entity); 368 return ret; 369 } 370