Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * vimc-common.c Virtual Media Controller Driver
0004  *
0005  * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
0006  */
0007 
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 
0011 #include "vimc-common.h"
0012 
0013 /*
0014  * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
0015  * in the scaler)
0016  */
0017 static const struct vimc_pix_map vimc_pix_map_list[] = {
0018     /* TODO: add all missing formats */
0019 
0020     /* RGB formats */
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     /* Bayer formats */
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     /* 10bit raw bayer a-law compressed to 8 bits */
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     /* 10bit raw bayer DPCM compressed to 8 bits */
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         /* src */
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         /* sink */
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     /* The width, height and pixelformat must match. */
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      * The field order must match, or the sink field order must be NONE
0312      * to support interlaced hardware connected to bridges that support
0313      * progressive formats only.
0314      */
0315     if (source_fmt.field != sink_fmt.field &&
0316         sink_fmt.field != V4L2_FIELD_NONE)
0317         return -EPIPE;
0318 
0319     /*
0320      * If colorspace is DEFAULT, then assume all the colorimetry is also
0321      * DEFAULT, return 0 to skip comparing the other colorimetry parameters
0322      */
0323     if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
0324         sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
0325         return 0;
0326 
0327     /* Colorspace must match. */
0328     if (source_fmt.colorspace != sink_fmt.colorspace)
0329         return -EPIPE;
0330 
0331     /* Colorimetry must match if they are not set to DEFAULT */
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     /* Fill the vimc_ent_device struct */
0366     ved->ent = &sd->entity;
0367 
0368     /* Initialize the subdev */
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     /* Expose this subdev to user space */
0377     sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
0378     if (sd->ctrl_handler)
0379         sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
0380 
0381     /* Initialize the media entity */
0382     ret = media_entity_pads_init(&sd->entity, num_pads, pads);
0383     if (ret)
0384         return ret;
0385 
0386     /* Register the subdev with the v4l2 and the media framework */
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 }