0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010
0011 #include "vimc-common.h"
0012
0013
0014
0015
0016
0017 static const struct vimc_pix_map vimc_pix_map_list[] = {
0018
0019
0020
0021 {
0022 .code = {
0023 MEDIA_BUS_FMT_BGR888_1X24,
0024 MEDIA_BUS_FMT_BGR888_3X8
0025 },
0026 .pixelformat = V4L2_PIX_FMT_BGR24,
0027 .bpp = 3,
0028 .bayer = false,
0029 },
0030 {
0031 .code = {
0032 MEDIA_BUS_FMT_RGB888_1X24,
0033 MEDIA_BUS_FMT_RGB888_2X12_BE,
0034 MEDIA_BUS_FMT_RGB888_2X12_LE,
0035 MEDIA_BUS_FMT_RGB888_3X8,
0036 MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
0037 MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
0038 MEDIA_BUS_FMT_RGB888_1X32_PADHI,
0039 MEDIA_BUS_FMT_GBR888_1X24
0040 },
0041 .pixelformat = V4L2_PIX_FMT_RGB24,
0042 .bpp = 3,
0043 .bayer = false,
0044 },
0045 {
0046 .code = { MEDIA_BUS_FMT_ARGB8888_1X32 },
0047 .pixelformat = V4L2_PIX_FMT_ARGB32,
0048 .bpp = 4,
0049 .bayer = false,
0050 },
0051
0052
0053 {
0054 .code = { MEDIA_BUS_FMT_SBGGR8_1X8 },
0055 .pixelformat = V4L2_PIX_FMT_SBGGR8,
0056 .bpp = 1,
0057 .bayer = true,
0058 },
0059 {
0060 .code = { MEDIA_BUS_FMT_SGBRG8_1X8 },
0061 .pixelformat = V4L2_PIX_FMT_SGBRG8,
0062 .bpp = 1,
0063 .bayer = true,
0064 },
0065 {
0066 .code = { MEDIA_BUS_FMT_SGRBG8_1X8 },
0067 .pixelformat = V4L2_PIX_FMT_SGRBG8,
0068 .bpp = 1,
0069 .bayer = true,
0070 },
0071 {
0072 .code = { MEDIA_BUS_FMT_SRGGB8_1X8 },
0073 .pixelformat = V4L2_PIX_FMT_SRGGB8,
0074 .bpp = 1,
0075 .bayer = true,
0076 },
0077 {
0078 .code = { MEDIA_BUS_FMT_SBGGR10_1X10 },
0079 .pixelformat = V4L2_PIX_FMT_SBGGR10,
0080 .bpp = 2,
0081 .bayer = true,
0082 },
0083 {
0084 .code = { MEDIA_BUS_FMT_SGBRG10_1X10 },
0085 .pixelformat = V4L2_PIX_FMT_SGBRG10,
0086 .bpp = 2,
0087 .bayer = true,
0088 },
0089 {
0090 .code = { MEDIA_BUS_FMT_SGRBG10_1X10 },
0091 .pixelformat = V4L2_PIX_FMT_SGRBG10,
0092 .bpp = 2,
0093 .bayer = true,
0094 },
0095 {
0096 .code = { MEDIA_BUS_FMT_SRGGB10_1X10 },
0097 .pixelformat = V4L2_PIX_FMT_SRGGB10,
0098 .bpp = 2,
0099 .bayer = true,
0100 },
0101
0102
0103 {
0104 .code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
0105 .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
0106 .bpp = 1,
0107 .bayer = true,
0108 },
0109 {
0110 .code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
0111 .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
0112 .bpp = 1,
0113 .bayer = true,
0114 },
0115 {
0116 .code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
0117 .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
0118 .bpp = 1,
0119 .bayer = true,
0120 },
0121 {
0122 .code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
0123 .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
0124 .bpp = 1,
0125 .bayer = true,
0126 },
0127
0128
0129 {
0130 .code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
0131 .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
0132 .bpp = 1,
0133 .bayer = true,
0134 },
0135 {
0136 .code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
0137 .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
0138 .bpp = 1,
0139 .bayer = true,
0140 },
0141 {
0142 .code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
0143 .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
0144 .bpp = 1,
0145 .bayer = true,
0146 },
0147 {
0148 .code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
0149 .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
0150 .bpp = 1,
0151 .bayer = true,
0152 },
0153 {
0154 .code = { MEDIA_BUS_FMT_SBGGR12_1X12 },
0155 .pixelformat = V4L2_PIX_FMT_SBGGR12,
0156 .bpp = 2,
0157 .bayer = true,
0158 },
0159 {
0160 .code = { MEDIA_BUS_FMT_SGBRG12_1X12 },
0161 .pixelformat = V4L2_PIX_FMT_SGBRG12,
0162 .bpp = 2,
0163 .bayer = true,
0164 },
0165 {
0166 .code = { MEDIA_BUS_FMT_SGRBG12_1X12 },
0167 .pixelformat = V4L2_PIX_FMT_SGRBG12,
0168 .bpp = 2,
0169 .bayer = true,
0170 },
0171 {
0172 .code = { MEDIA_BUS_FMT_SRGGB12_1X12 },
0173 .pixelformat = V4L2_PIX_FMT_SRGGB12,
0174 .bpp = 2,
0175 .bayer = true,
0176 },
0177 };
0178
0179 bool vimc_is_source(struct media_entity *ent)
0180 {
0181 unsigned int i;
0182
0183 for (i = 0; i < ent->num_pads; i++)
0184 if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
0185 return false;
0186 return true;
0187 }
0188
0189 const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
0190 {
0191 if (i >= ARRAY_SIZE(vimc_pix_map_list))
0192 return NULL;
0193
0194 return &vimc_pix_map_list[i];
0195 }
0196
0197 u32 vimc_mbus_code_by_index(unsigned int index)
0198 {
0199 unsigned int i, j;
0200
0201 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
0202 for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
0203 if (!vimc_pix_map_list[i].code[j])
0204 break;
0205
0206 if (!index)
0207 return vimc_pix_map_list[i].code[j];
0208 index--;
0209 }
0210 }
0211 return 0;
0212 }
0213
0214 const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
0215 {
0216 unsigned int i, j;
0217
0218 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
0219 for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {
0220 if (vimc_pix_map_list[i].code[j] == code)
0221 return &vimc_pix_map_list[i];
0222 }
0223 }
0224 return NULL;
0225 }
0226
0227 const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
0228 {
0229 unsigned int i;
0230
0231 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
0232 if (vimc_pix_map_list[i].pixelformat == pixelformat)
0233 return &vimc_pix_map_list[i];
0234 }
0235 return NULL;
0236 }
0237
0238 static int vimc_get_pix_format(struct media_pad *pad,
0239 struct v4l2_pix_format *fmt)
0240 {
0241 if (is_media_entity_v4l2_subdev(pad->entity)) {
0242 struct v4l2_subdev *sd =
0243 media_entity_to_v4l2_subdev(pad->entity);
0244 struct v4l2_subdev_format sd_fmt;
0245 const struct vimc_pix_map *pix_map;
0246 int ret;
0247
0248 sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
0249 sd_fmt.pad = pad->index;
0250
0251 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
0252 if (ret)
0253 return ret;
0254
0255 v4l2_fill_pix_format(fmt, &sd_fmt.format);
0256 pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
0257 fmt->pixelformat = pix_map->pixelformat;
0258 } else if (is_media_entity_v4l2_video_device(pad->entity)) {
0259 struct video_device *vdev = container_of(pad->entity,
0260 struct video_device,
0261 entity);
0262 struct vimc_ent_device *ved = video_get_drvdata(vdev);
0263
0264 if (!ved->vdev_get_format)
0265 return -ENOIOCTLCMD;
0266
0267 ved->vdev_get_format(ved, fmt);
0268 } else {
0269 return -EINVAL;
0270 }
0271
0272 return 0;
0273 }
0274
0275 int vimc_vdev_link_validate(struct media_link *link)
0276 {
0277 struct v4l2_pix_format source_fmt, sink_fmt;
0278 int ret;
0279
0280 ret = vimc_get_pix_format(link->source, &source_fmt);
0281 if (ret)
0282 return ret;
0283
0284 ret = vimc_get_pix_format(link->sink, &sink_fmt);
0285 if (ret)
0286 return ret;
0287
0288 pr_info("vimc link validate: "
0289 "%s:src:%dx%d (0x%x, %d, %d, %d, %d) "
0290 "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
0291
0292 link->source->entity->name,
0293 source_fmt.width, source_fmt.height,
0294 source_fmt.pixelformat, source_fmt.colorspace,
0295 source_fmt.quantization, source_fmt.xfer_func,
0296 source_fmt.ycbcr_enc,
0297
0298 link->sink->entity->name,
0299 sink_fmt.width, sink_fmt.height,
0300 sink_fmt.pixelformat, sink_fmt.colorspace,
0301 sink_fmt.quantization, sink_fmt.xfer_func,
0302 sink_fmt.ycbcr_enc);
0303
0304
0305 if (source_fmt.width != sink_fmt.width ||
0306 source_fmt.height != sink_fmt.height ||
0307 source_fmt.pixelformat != sink_fmt.pixelformat)
0308 return -EPIPE;
0309
0310
0311
0312
0313
0314
0315 if (source_fmt.field != sink_fmt.field &&
0316 sink_fmt.field != V4L2_FIELD_NONE)
0317 return -EPIPE;
0318
0319
0320
0321
0322
0323 if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
0324 sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
0325 return 0;
0326
0327
0328 if (source_fmt.colorspace != sink_fmt.colorspace)
0329 return -EPIPE;
0330
0331
0332 if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
0333 sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
0334 source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
0335 return -EPIPE;
0336
0337 if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
0338 sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
0339 source_fmt.quantization != sink_fmt.quantization)
0340 return -EPIPE;
0341
0342 if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
0343 sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
0344 source_fmt.xfer_func != sink_fmt.xfer_func)
0345 return -EPIPE;
0346
0347 return 0;
0348 }
0349
0350 static const struct media_entity_operations vimc_ent_sd_mops = {
0351 .link_validate = v4l2_subdev_link_validate,
0352 };
0353
0354 int vimc_ent_sd_register(struct vimc_ent_device *ved,
0355 struct v4l2_subdev *sd,
0356 struct v4l2_device *v4l2_dev,
0357 const char *const name,
0358 u32 function,
0359 u16 num_pads,
0360 struct media_pad *pads,
0361 const struct v4l2_subdev_ops *sd_ops)
0362 {
0363 int ret;
0364
0365
0366 ved->ent = &sd->entity;
0367
0368
0369 v4l2_subdev_init(sd, sd_ops);
0370 sd->entity.function = function;
0371 sd->entity.ops = &vimc_ent_sd_mops;
0372 sd->owner = THIS_MODULE;
0373 strscpy(sd->name, name, sizeof(sd->name));
0374 v4l2_set_subdevdata(sd, ved);
0375
0376
0377 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
0378 if (sd->ctrl_handler)
0379 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
0380
0381
0382 ret = media_entity_pads_init(&sd->entity, num_pads, pads);
0383 if (ret)
0384 return ret;
0385
0386
0387 ret = v4l2_device_register_subdev(v4l2_dev, sd);
0388 if (ret) {
0389 dev_err(v4l2_dev->dev,
0390 "%s: subdev register failed (err=%d)\n",
0391 name, ret);
0392 goto err_clean_m_ent;
0393 }
0394
0395 return 0;
0396
0397 err_clean_m_ent:
0398 media_entity_cleanup(&sd->entity);
0399 return ret;
0400 }