linux/drivers/media/platform/vsp1/vsp1_entity.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * vsp1_entity.c  --  R-Car VSP1 Base Entity
   4 *
   5 * Copyright (C) 2013-2014 Renesas Electronics Corporation
   6 *
   7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   8 */
   9
  10#include <linux/device.h>
  11#include <linux/gfp.h>
  12
  13#include <media/media-entity.h>
  14#include <media/v4l2-ctrls.h>
  15#include <media/v4l2-subdev.h>
  16
  17#include "vsp1.h"
  18#include "vsp1_dl.h"
  19#include "vsp1_entity.h"
  20#include "vsp1_pipe.h"
  21#include "vsp1_rwpf.h"
  22
  23void vsp1_entity_route_setup(struct vsp1_entity *entity,
  24                             struct vsp1_pipeline *pipe,
  25                             struct vsp1_dl_body *dlb)
  26{
  27        struct vsp1_entity *source;
  28        u32 route;
  29
  30        if (entity->type == VSP1_ENTITY_HGO) {
  31                u32 smppt;
  32
  33                /*
  34                 * The HGO is a special case, its routing is configured on the
  35                 * sink pad.
  36                 */
  37                source = entity->sources[0];
  38                smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT)
  39                      | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT);
  40
  41                vsp1_dl_body_write(dlb, VI6_DPR_HGO_SMPPT, smppt);
  42                return;
  43        } else if (entity->type == VSP1_ENTITY_HGT) {
  44                u32 smppt;
  45
  46                /*
  47                 * The HGT is a special case, its routing is configured on the
  48                 * sink pad.
  49                 */
  50                source = entity->sources[0];
  51                smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT)
  52                      | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT);
  53
  54                vsp1_dl_body_write(dlb, VI6_DPR_HGT_SMPPT, smppt);
  55                return;
  56        }
  57
  58        source = entity;
  59        if (source->route->reg == 0)
  60                return;
  61
  62        route = source->sink->route->inputs[source->sink_pad];
  63        /*
  64         * The ILV and BRS share the same data path route. The extra BRSSEL bit
  65         * selects between the ILV and BRS.
  66         */
  67        if (source->type == VSP1_ENTITY_BRS)
  68                route |= VI6_DPR_ROUTE_BRSSEL;
  69        vsp1_dl_body_write(dlb, source->route->reg, route);
  70}
  71
  72void vsp1_entity_configure_stream(struct vsp1_entity *entity,
  73                                  struct vsp1_pipeline *pipe,
  74                                  struct vsp1_dl_body *dlb)
  75{
  76        if (entity->ops->configure_stream)
  77                entity->ops->configure_stream(entity, pipe, dlb);
  78}
  79
  80void vsp1_entity_configure_frame(struct vsp1_entity *entity,
  81                                 struct vsp1_pipeline *pipe,
  82                                 struct vsp1_dl_list *dl,
  83                                 struct vsp1_dl_body *dlb)
  84{
  85        if (entity->ops->configure_frame)
  86                entity->ops->configure_frame(entity, pipe, dl, dlb);
  87}
  88
  89void vsp1_entity_configure_partition(struct vsp1_entity *entity,
  90                                     struct vsp1_pipeline *pipe,
  91                                     struct vsp1_dl_list *dl,
  92                                     struct vsp1_dl_body *dlb)
  93{
  94        if (entity->ops->configure_partition)
  95                entity->ops->configure_partition(entity, pipe, dl, dlb);
  96}
  97
  98/* -----------------------------------------------------------------------------
  99 * V4L2 Subdevice Operations
 100 */
 101
 102/**
 103 * vsp1_entity_get_pad_config - Get the pad configuration for an entity
 104 * @entity: the entity
 105 * @cfg: the TRY pad configuration
 106 * @which: configuration selector (ACTIVE or TRY)
 107 *
 108 * When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold
 109 * the entity lock to access the returned configuration.
 110 *
 111 * Return the pad configuration requested by the which argument. The TRY
 112 * configuration is passed explicitly to the function through the cfg argument
 113 * and simply returned when requested. The ACTIVE configuration comes from the
 114 * entity structure.
 115 */
 116struct v4l2_subdev_pad_config *
 117vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 118                           struct v4l2_subdev_pad_config *cfg,
 119                           enum v4l2_subdev_format_whence which)
 120{
 121        switch (which) {
 122        case V4L2_SUBDEV_FORMAT_ACTIVE:
 123                return entity->config;
 124        case V4L2_SUBDEV_FORMAT_TRY:
 125        default:
 126                return cfg;
 127        }
 128}
 129
 130/**
 131 * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
 132 * @entity: the entity
 133 * @cfg: the configuration storage
 134 * @pad: the pad number
 135 *
 136 * Return the format stored in the given configuration for an entity's pad. The
 137 * configuration can be an ACTIVE or TRY configuration.
 138 */
 139struct v4l2_mbus_framefmt *
 140vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 141                           struct v4l2_subdev_pad_config *cfg,
 142                           unsigned int pad)
 143{
 144        return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
 145}
 146
 147/**
 148 * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
 149 * @entity: the entity
 150 * @cfg: the configuration storage
 151 * @pad: the pad number
 152 * @target: the selection target
 153 *
 154 * Return the selection rectangle stored in the given configuration for an
 155 * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
 156 * selection target can be COMPOSE or CROP.
 157 */
 158struct v4l2_rect *
 159vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
 160                              struct v4l2_subdev_pad_config *cfg,
 161                              unsigned int pad, unsigned int target)
 162{
 163        switch (target) {
 164        case V4L2_SEL_TGT_COMPOSE:
 165                return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
 166        case V4L2_SEL_TGT_CROP:
 167                return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
 168        default:
 169                return NULL;
 170        }
 171}
 172
 173/*
 174 * vsp1_entity_init_cfg - Initialize formats on all pads
 175 * @subdev: V4L2 subdevice
 176 * @cfg: V4L2 subdev pad configuration
 177 *
 178 * Initialize all pad formats with default values in the given pad config. This
 179 * function can be used as a handler for the subdev pad::init_cfg operation.
 180 */
 181int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 182                         struct v4l2_subdev_pad_config *cfg)
 183{
 184        struct v4l2_subdev_format format;
 185        unsigned int pad;
 186
 187        for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
 188                memset(&format, 0, sizeof(format));
 189
 190                format.pad = pad;
 191                format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
 192                             : V4L2_SUBDEV_FORMAT_ACTIVE;
 193
 194                v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
 195        }
 196
 197        return 0;
 198}
 199
 200/*
 201 * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
 202 * @subdev: V4L2 subdevice
 203 * @cfg: V4L2 subdev pad configuration
 204 * @fmt: V4L2 subdev format
 205 *
 206 * This function implements the subdev get_fmt pad operation. It can be used as
 207 * a direct drop-in for the operation handler.
 208 */
 209int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
 210                               struct v4l2_subdev_pad_config *cfg,
 211                               struct v4l2_subdev_format *fmt)
 212{
 213        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 214        struct v4l2_subdev_pad_config *config;
 215
 216        config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
 217        if (!config)
 218                return -EINVAL;
 219
 220        mutex_lock(&entity->lock);
 221        fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad);
 222        mutex_unlock(&entity->lock);
 223
 224        return 0;
 225}
 226
 227/*
 228 * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
 229 * @subdev: V4L2 subdevice
 230 * @cfg: V4L2 subdev pad configuration
 231 * @code: Media bus code enumeration
 232 * @codes: Array of supported media bus codes
 233 * @ncodes: Number of supported media bus codes
 234 *
 235 * This function implements the subdev enum_mbus_code pad operation for entities
 236 * that do not support format conversion. It enumerates the given supported
 237 * media bus codes on the sink pad and reports a source pad format identical to
 238 * the sink pad.
 239 */
 240int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
 241                               struct v4l2_subdev_pad_config *cfg,
 242                               struct v4l2_subdev_mbus_code_enum *code,
 243                               const unsigned int *codes, unsigned int ncodes)
 244{
 245        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 246
 247        if (code->pad == 0) {
 248                if (code->index >= ncodes)
 249                        return -EINVAL;
 250
 251                code->code = codes[code->index];
 252        } else {
 253                struct v4l2_subdev_pad_config *config;
 254                struct v4l2_mbus_framefmt *format;
 255
 256                /*
 257                 * The entity can't perform format conversion, the sink format
 258                 * is always identical to the source format.
 259                 */
 260                if (code->index)
 261                        return -EINVAL;
 262
 263                config = vsp1_entity_get_pad_config(entity, cfg, code->which);
 264                if (!config)
 265                        return -EINVAL;
 266
 267                mutex_lock(&entity->lock);
 268                format = vsp1_entity_get_pad_format(entity, config, 0);
 269                code->code = format->code;
 270                mutex_unlock(&entity->lock);
 271        }
 272
 273        return 0;
 274}
 275
 276/*
 277 * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
 278 * @subdev: V4L2 subdevice
 279 * @cfg: V4L2 subdev pad configuration
 280 * @fse: Frame size enumeration
 281 * @min_width: Minimum image width
 282 * @min_height: Minimum image height
 283 * @max_width: Maximum image width
 284 * @max_height: Maximum image height
 285 *
 286 * This function implements the subdev enum_frame_size pad operation for
 287 * entities that do not support scaling or cropping. It reports the given
 288 * minimum and maximum frame width and height on the sink pad, and a fixed
 289 * source pad size identical to the sink pad.
 290 */
 291int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
 292                                struct v4l2_subdev_pad_config *cfg,
 293                                struct v4l2_subdev_frame_size_enum *fse,
 294                                unsigned int min_width, unsigned int min_height,
 295                                unsigned int max_width, unsigned int max_height)
 296{
 297        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 298        struct v4l2_subdev_pad_config *config;
 299        struct v4l2_mbus_framefmt *format;
 300        int ret = 0;
 301
 302        config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
 303        if (!config)
 304                return -EINVAL;
 305
 306        format = vsp1_entity_get_pad_format(entity, config, fse->pad);
 307
 308        mutex_lock(&entity->lock);
 309
 310        if (fse->index || fse->code != format->code) {
 311                ret = -EINVAL;
 312                goto done;
 313        }
 314
 315        if (fse->pad == 0) {
 316                fse->min_width = min_width;
 317                fse->max_width = max_width;
 318                fse->min_height = min_height;
 319                fse->max_height = max_height;
 320        } else {
 321                /*
 322                 * The size on the source pad are fixed and always identical to
 323                 * the size on the sink pad.
 324                 */
 325                fse->min_width = format->width;
 326                fse->max_width = format->width;
 327                fse->min_height = format->height;
 328                fse->max_height = format->height;
 329        }
 330
 331done:
 332        mutex_unlock(&entity->lock);
 333        return ret;
 334}
 335
 336/*
 337 * vsp1_subdev_set_pad_format - Subdev pad set_fmt handler
 338 * @subdev: V4L2 subdevice
 339 * @cfg: V4L2 subdev pad configuration
 340 * @fmt: V4L2 subdev format
 341 * @codes: Array of supported media bus codes
 342 * @ncodes: Number of supported media bus codes
 343 * @min_width: Minimum image width
 344 * @min_height: Minimum image height
 345 * @max_width: Maximum image width
 346 * @max_height: Maximum image height
 347 *
 348 * This function implements the subdev set_fmt pad operation for entities that
 349 * do not support scaling or cropping. It defaults to the first supplied media
 350 * bus code if the requested code isn't supported, clamps the size to the
 351 * supplied minimum and maximum, and propagates the sink pad format to the
 352 * source pad.
 353 */
 354int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
 355                               struct v4l2_subdev_pad_config *cfg,
 356                               struct v4l2_subdev_format *fmt,
 357                               const unsigned int *codes, unsigned int ncodes,
 358                               unsigned int min_width, unsigned int min_height,
 359                               unsigned int max_width, unsigned int max_height)
 360{
 361        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 362        struct v4l2_subdev_pad_config *config;
 363        struct v4l2_mbus_framefmt *format;
 364        struct v4l2_rect *selection;
 365        unsigned int i;
 366        int ret = 0;
 367
 368        mutex_lock(&entity->lock);
 369
 370        config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
 371        if (!config) {
 372                ret = -EINVAL;
 373                goto done;
 374        }
 375
 376        format = vsp1_entity_get_pad_format(entity, config, fmt->pad);
 377
 378        if (fmt->pad == entity->source_pad) {
 379                /* The output format can't be modified. */
 380                fmt->format = *format;
 381                goto done;
 382        }
 383
 384        /*
 385         * Default to the first media bus code if the requested format is not
 386         * supported.
 387         */
 388        for (i = 0; i < ncodes; ++i) {
 389                if (fmt->format.code == codes[i])
 390                        break;
 391        }
 392
 393        format->code = i < ncodes ? codes[i] : codes[0];
 394        format->width = clamp_t(unsigned int, fmt->format.width,
 395                                min_width, max_width);
 396        format->height = clamp_t(unsigned int, fmt->format.height,
 397                                 min_height, max_height);
 398        format->field = V4L2_FIELD_NONE;
 399        format->colorspace = V4L2_COLORSPACE_SRGB;
 400
 401        fmt->format = *format;
 402
 403        /* Propagate the format to the source pad. */
 404        format = vsp1_entity_get_pad_format(entity, config, entity->source_pad);
 405        *format = fmt->format;
 406
 407        /* Reset the crop and compose rectangles */
 408        selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad,
 409                                                  V4L2_SEL_TGT_CROP);
 410        selection->left = 0;
 411        selection->top = 0;
 412        selection->width = format->width;
 413        selection->height = format->height;
 414
 415        selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad,
 416                                                  V4L2_SEL_TGT_COMPOSE);
 417        selection->left = 0;
 418        selection->top = 0;
 419        selection->width = format->width;
 420        selection->height = format->height;
 421
 422done:
 423        mutex_unlock(&entity->lock);
 424        return ret;
 425}
 426
 427/* -----------------------------------------------------------------------------
 428 * Media Operations
 429 */
 430
 431static inline struct vsp1_entity *
 432media_entity_to_vsp1_entity(struct media_entity *entity)
 433{
 434        return container_of(entity, struct vsp1_entity, subdev.entity);
 435}
 436
 437static int vsp1_entity_link_setup_source(const struct media_pad *source_pad,
 438                                         const struct media_pad *sink_pad,
 439                                         u32 flags)
 440{
 441        struct vsp1_entity *source;
 442
 443        source = media_entity_to_vsp1_entity(source_pad->entity);
 444
 445        if (!source->route)
 446                return 0;
 447
 448        if (flags & MEDIA_LNK_FL_ENABLED) {
 449                struct vsp1_entity *sink
 450                        = media_entity_to_vsp1_entity(sink_pad->entity);
 451
 452                /*
 453                 * Fan-out is limited to one for the normal data path plus
 454                 * optional HGO and HGT. We ignore the HGO and HGT here.
 455                 */
 456                if (sink->type != VSP1_ENTITY_HGO &&
 457                    sink->type != VSP1_ENTITY_HGT) {
 458                        if (source->sink)
 459                                return -EBUSY;
 460                        source->sink = sink;
 461                        source->sink_pad = sink_pad->index;
 462                }
 463        } else {
 464                source->sink = NULL;
 465                source->sink_pad = 0;
 466        }
 467
 468        return 0;
 469}
 470
 471static int vsp1_entity_link_setup_sink(const struct media_pad *source_pad,
 472                                       const struct media_pad *sink_pad,
 473                                       u32 flags)
 474{
 475        struct vsp1_entity *sink;
 476        struct vsp1_entity *source;
 477
 478        sink = media_entity_to_vsp1_entity(sink_pad->entity);
 479        source = media_entity_to_vsp1_entity(source_pad->entity);
 480
 481        if (flags & MEDIA_LNK_FL_ENABLED) {
 482                /* Fan-in is limited to one. */
 483                if (sink->sources[sink_pad->index])
 484                        return -EBUSY;
 485
 486                sink->sources[sink_pad->index] = source;
 487        } else {
 488                sink->sources[sink_pad->index] = NULL;
 489        }
 490
 491        return 0;
 492}
 493
 494int vsp1_entity_link_setup(struct media_entity *entity,
 495                           const struct media_pad *local,
 496                           const struct media_pad *remote, u32 flags)
 497{
 498        if (local->flags & MEDIA_PAD_FL_SOURCE)
 499                return vsp1_entity_link_setup_source(local, remote, flags);
 500        else
 501                return vsp1_entity_link_setup_sink(remote, local, flags);
 502}
 503
 504/**
 505 * vsp1_entity_remote_pad - Find the pad at the remote end of a link
 506 * @pad: Pad at the local end of the link
 507 *
 508 * Search for a remote pad connected to the given pad by iterating over all
 509 * links originating or terminating at that pad until an enabled link is found.
 510 *
 511 * Our link setup implementation guarantees that the output fan-out will not be
 512 * higher than one for the data pipelines, except for the links to the HGO and
 513 * HGT that can be enabled in addition to a regular data link. When traversing
 514 * outgoing links this function ignores HGO and HGT entities and should thus be
 515 * used in place of the generic media_entity_remote_pad() function to traverse
 516 * data pipelines.
 517 *
 518 * Return a pointer to the pad at the remote end of the first found enabled
 519 * link, or NULL if no enabled link has been found.
 520 */
 521struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad)
 522{
 523        struct media_link *link;
 524
 525        list_for_each_entry(link, &pad->entity->links, list) {
 526                struct vsp1_entity *entity;
 527
 528                if (!(link->flags & MEDIA_LNK_FL_ENABLED))
 529                        continue;
 530
 531                /* If we're the sink the source will never be an HGO or HGT. */
 532                if (link->sink == pad)
 533                        return link->source;
 534
 535                if (link->source != pad)
 536                        continue;
 537
 538                /* If the sink isn't a subdevice it can't be an HGO or HGT. */
 539                if (!is_media_entity_v4l2_subdev(link->sink->entity))
 540                        return link->sink;
 541
 542                entity = media_entity_to_vsp1_entity(link->sink->entity);
 543                if (entity->type != VSP1_ENTITY_HGO &&
 544                    entity->type != VSP1_ENTITY_HGT)
 545                        return link->sink;
 546        }
 547
 548        return NULL;
 549
 550}
 551
 552/* -----------------------------------------------------------------------------
 553 * Initialization
 554 */
 555
 556#define VSP1_ENTITY_ROUTE(ent)                                          \
 557        { VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE,                  \
 558          { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent }
 559
 560#define VSP1_ENTITY_ROUTE_RPF(idx)                                      \
 561        { VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx),                 \
 562          { 0, }, VI6_DPR_NODE_RPF(idx) }
 563
 564#define VSP1_ENTITY_ROUTE_UDS(idx)                                      \
 565        { VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx),                 \
 566          { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) }
 567
 568#define VSP1_ENTITY_ROUTE_UIF(idx)                                      \
 569        { VSP1_ENTITY_UIF, idx, VI6_DPR_UIF_ROUTE(idx),                 \
 570          { VI6_DPR_NODE_UIF(idx) }, VI6_DPR_NODE_UIF(idx) }
 571
 572#define VSP1_ENTITY_ROUTE_WPF(idx)                                      \
 573        { VSP1_ENTITY_WPF, idx, 0,                                      \
 574          { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) }
 575
 576static const struct vsp1_route vsp1_routes[] = {
 577        { VSP1_ENTITY_BRS, 0, VI6_DPR_ILV_BRS_ROUTE,
 578          { VI6_DPR_NODE_BRS_IN(0), VI6_DPR_NODE_BRS_IN(1) }, 0 },
 579        { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
 580          { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
 581            VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3),
 582            VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT },
 583        VSP1_ENTITY_ROUTE(CLU),
 584        { VSP1_ENTITY_HGO, 0, 0, { 0, }, 0 },
 585        { VSP1_ENTITY_HGT, 0, 0, { 0, }, 0 },
 586        VSP1_ENTITY_ROUTE(HSI),
 587        VSP1_ENTITY_ROUTE(HST),
 588        { VSP1_ENTITY_LIF, 0, 0, { 0, }, 0 },
 589        { VSP1_ENTITY_LIF, 1, 0, { 0, }, 0 },
 590        VSP1_ENTITY_ROUTE(LUT),
 591        VSP1_ENTITY_ROUTE_RPF(0),
 592        VSP1_ENTITY_ROUTE_RPF(1),
 593        VSP1_ENTITY_ROUTE_RPF(2),
 594        VSP1_ENTITY_ROUTE_RPF(3),
 595        VSP1_ENTITY_ROUTE_RPF(4),
 596        VSP1_ENTITY_ROUTE(SRU),
 597        VSP1_ENTITY_ROUTE_UDS(0),
 598        VSP1_ENTITY_ROUTE_UDS(1),
 599        VSP1_ENTITY_ROUTE_UDS(2),
 600        VSP1_ENTITY_ROUTE_UIF(0),       /* Named UIF4 in the documentation */
 601        VSP1_ENTITY_ROUTE_UIF(1),       /* Named UIF5 in the documentation */
 602        VSP1_ENTITY_ROUTE_WPF(0),
 603        VSP1_ENTITY_ROUTE_WPF(1),
 604        VSP1_ENTITY_ROUTE_WPF(2),
 605        VSP1_ENTITY_ROUTE_WPF(3),
 606};
 607
 608int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 609                     const char *name, unsigned int num_pads,
 610                     const struct v4l2_subdev_ops *ops, u32 function)
 611{
 612        struct v4l2_subdev *subdev;
 613        unsigned int i;
 614        int ret;
 615
 616        for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
 617                if (vsp1_routes[i].type == entity->type &&
 618                    vsp1_routes[i].index == entity->index) {
 619                        entity->route = &vsp1_routes[i];
 620                        break;
 621                }
 622        }
 623
 624        if (i == ARRAY_SIZE(vsp1_routes))
 625                return -EINVAL;
 626
 627        mutex_init(&entity->lock);
 628
 629        entity->vsp1 = vsp1;
 630        entity->source_pad = num_pads - 1;
 631
 632        /* Allocate and initialize pads. */
 633        entity->pads = devm_kcalloc(vsp1->dev,
 634                                    num_pads, sizeof(*entity->pads),
 635                                    GFP_KERNEL);
 636        if (entity->pads == NULL)
 637                return -ENOMEM;
 638
 639        for (i = 0; i < num_pads - 1; ++i)
 640                entity->pads[i].flags = MEDIA_PAD_FL_SINK;
 641
 642        entity->sources = devm_kcalloc(vsp1->dev, max(num_pads - 1, 1U),
 643                                       sizeof(*entity->sources), GFP_KERNEL);
 644        if (entity->sources == NULL)
 645                return -ENOMEM;
 646
 647        /* Single-pad entities only have a sink. */
 648        entity->pads[num_pads - 1].flags = num_pads > 1 ? MEDIA_PAD_FL_SOURCE
 649                                         : MEDIA_PAD_FL_SINK;
 650
 651        /* Initialize the media entity. */
 652        ret = media_entity_pads_init(&entity->subdev.entity, num_pads,
 653                                     entity->pads);
 654        if (ret < 0)
 655                return ret;
 656
 657        /* Initialize the V4L2 subdev. */
 658        subdev = &entity->subdev;
 659        v4l2_subdev_init(subdev, ops);
 660
 661        subdev->entity.function = function;
 662        subdev->entity.ops = &vsp1->media_ops;
 663        subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 664
 665        snprintf(subdev->name, sizeof(subdev->name), "%s %s",
 666                 dev_name(vsp1->dev), name);
 667
 668        vsp1_entity_init_cfg(subdev, NULL);
 669
 670        /*
 671         * Allocate the pad configuration to store formats and selection
 672         * rectangles.
 673         */
 674        entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
 675        if (entity->config == NULL) {
 676                media_entity_cleanup(&entity->subdev.entity);
 677                return -ENOMEM;
 678        }
 679
 680        return 0;
 681}
 682
 683void vsp1_entity_destroy(struct vsp1_entity *entity)
 684{
 685        if (entity->ops && entity->ops->destroy)
 686                entity->ops->destroy(entity);
 687        if (entity->subdev.ctrl_handler)
 688                v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 689        v4l2_subdev_free_pad_config(entity->config);
 690        media_entity_cleanup(&entity->subdev.entity);
 691}
 692