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