linux/drivers/media/platform/vsp1/vsp1_entity.c
<<
>>
Prefs
   1/*
   2 * vsp1_entity.c  --  R-Car VSP1 Base Entity
   3 *
   4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
   5 *
   6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/gfp.h>
  16
  17#include <media/media-entity.h>
  18#include <media/v4l2-ctrls.h>
  19#include <media/v4l2-subdev.h>
  20
  21#include "vsp1.h"
  22#include "vsp1_dl.h"
  23#include "vsp1_entity.h"
  24
  25static inline struct vsp1_entity *
  26media_entity_to_vsp1_entity(struct media_entity *entity)
  27{
  28        return container_of(entity, struct vsp1_entity, subdev.entity);
  29}
  30
  31void vsp1_entity_route_setup(struct vsp1_entity *source,
  32                             struct vsp1_dl_list *dl)
  33{
  34        struct vsp1_entity *sink;
  35
  36        if (source->route->reg == 0)
  37                return;
  38
  39        sink = media_entity_to_vsp1_entity(source->sink);
  40        vsp1_dl_list_write(dl, source->route->reg,
  41                           sink->route->inputs[source->sink_pad]);
  42}
  43
  44/* -----------------------------------------------------------------------------
  45 * V4L2 Subdevice Operations
  46 */
  47
  48/**
  49 * vsp1_entity_get_pad_config - Get the pad configuration for an entity
  50 * @entity: the entity
  51 * @cfg: the TRY pad configuration
  52 * @which: configuration selector (ACTIVE or TRY)
  53 *
  54 * Return the pad configuration requested by the which argument. The TRY
  55 * configuration is passed explicitly to the function through the cfg argument
  56 * and simply returned when requested. The ACTIVE configuration comes from the
  57 * entity structure.
  58 */
  59struct v4l2_subdev_pad_config *
  60vsp1_entity_get_pad_config(struct vsp1_entity *entity,
  61                           struct v4l2_subdev_pad_config *cfg,
  62                           enum v4l2_subdev_format_whence which)
  63{
  64        switch (which) {
  65        case V4L2_SUBDEV_FORMAT_ACTIVE:
  66                return entity->config;
  67        case V4L2_SUBDEV_FORMAT_TRY:
  68        default:
  69                return cfg;
  70        }
  71}
  72
  73/**
  74 * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
  75 * @entity: the entity
  76 * @cfg: the configuration storage
  77 * @pad: the pad number
  78 *
  79 * Return the format stored in the given configuration for an entity's pad. The
  80 * configuration can be an ACTIVE or TRY configuration.
  81 */
  82struct v4l2_mbus_framefmt *
  83vsp1_entity_get_pad_format(struct vsp1_entity *entity,
  84                           struct v4l2_subdev_pad_config *cfg,
  85                           unsigned int pad)
  86{
  87        return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
  88}
  89
  90/**
  91 * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
  92 * @entity: the entity
  93 * @cfg: the configuration storage
  94 * @pad: the pad number
  95 * @target: the selection target
  96 *
  97 * Return the selection rectangle stored in the given configuration for an
  98 * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
  99 * selection target can be COMPOSE or CROP.
 100 */
 101struct v4l2_rect *
 102vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
 103                              struct v4l2_subdev_pad_config *cfg,
 104                              unsigned int pad, unsigned int target)
 105{
 106        switch (target) {
 107        case V4L2_SEL_TGT_COMPOSE:
 108                return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
 109        case V4L2_SEL_TGT_CROP:
 110                return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
 111        default:
 112                return NULL;
 113        }
 114}
 115
 116/*
 117 * vsp1_entity_init_cfg - Initialize formats on all pads
 118 * @subdev: V4L2 subdevice
 119 * @cfg: V4L2 subdev pad configuration
 120 *
 121 * Initialize all pad formats with default values in the given pad config. This
 122 * function can be used as a handler for the subdev pad::init_cfg operation.
 123 */
 124int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 125                         struct v4l2_subdev_pad_config *cfg)
 126{
 127        struct v4l2_subdev_format format;
 128        unsigned int pad;
 129
 130        for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
 131                memset(&format, 0, sizeof(format));
 132
 133                format.pad = pad;
 134                format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
 135                             : V4L2_SUBDEV_FORMAT_ACTIVE;
 136
 137                v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
 138        }
 139
 140        return 0;
 141}
 142
 143/*
 144 * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
 145 * @subdev: V4L2 subdevice
 146 * @cfg: V4L2 subdev pad configuration
 147 * @fmt: V4L2 subdev format
 148 *
 149 * This function implements the subdev get_fmt pad operation. It can be used as
 150 * a direct drop-in for the operation handler.
 151 */
 152int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
 153                               struct v4l2_subdev_pad_config *cfg,
 154                               struct v4l2_subdev_format *fmt)
 155{
 156        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 157        struct v4l2_subdev_pad_config *config;
 158
 159        config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
 160        if (!config)
 161                return -EINVAL;
 162
 163        fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad);
 164
 165        return 0;
 166}
 167
 168/*
 169 * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
 170 * @subdev: V4L2 subdevice
 171 * @cfg: V4L2 subdev pad configuration
 172 * @code: Media bus code enumeration
 173 * @codes: Array of supported media bus codes
 174 * @ncodes: Number of supported media bus codes
 175 *
 176 * This function implements the subdev enum_mbus_code pad operation for entities
 177 * that do not support format conversion. It enumerates the given supported
 178 * media bus codes on the sink pad and reports a source pad format identical to
 179 * the sink pad.
 180 */
 181int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
 182                               struct v4l2_subdev_pad_config *cfg,
 183                               struct v4l2_subdev_mbus_code_enum *code,
 184                               const unsigned int *codes, unsigned int ncodes)
 185{
 186        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 187
 188        if (code->pad == 0) {
 189                if (code->index >= ncodes)
 190                        return -EINVAL;
 191
 192                code->code = codes[code->index];
 193        } else {
 194                struct v4l2_subdev_pad_config *config;
 195                struct v4l2_mbus_framefmt *format;
 196
 197                /* The entity can't perform format conversion, the sink format
 198                 * is always identical to the source format.
 199                 */
 200                if (code->index)
 201                        return -EINVAL;
 202
 203                config = vsp1_entity_get_pad_config(entity, cfg, code->which);
 204                if (!config)
 205                        return -EINVAL;
 206
 207                format = vsp1_entity_get_pad_format(entity, config, 0);
 208                code->code = format->code;
 209        }
 210
 211        return 0;
 212}
 213
 214/*
 215 * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
 216 * @subdev: V4L2 subdevice
 217 * @cfg: V4L2 subdev pad configuration
 218 * @fse: Frame size enumeration
 219 * @min_width: Minimum image width
 220 * @min_height: Minimum image height
 221 * @max_width: Maximum image width
 222 * @max_height: Maximum image height
 223 *
 224 * This function implements the subdev enum_frame_size pad operation for
 225 * entities that do not support scaling or cropping. It reports the given
 226 * minimum and maximum frame width and height on the sink pad, and a fixed
 227 * source pad size identical to the sink pad.
 228 */
 229int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
 230                                struct v4l2_subdev_pad_config *cfg,
 231                                struct v4l2_subdev_frame_size_enum *fse,
 232                                unsigned int min_width, unsigned int min_height,
 233                                unsigned int max_width, unsigned int max_height)
 234{
 235        struct vsp1_entity *entity = to_vsp1_entity(subdev);
 236        struct v4l2_subdev_pad_config *config;
 237        struct v4l2_mbus_framefmt *format;
 238
 239        config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
 240        if (!config)
 241                return -EINVAL;
 242
 243        format = vsp1_entity_get_pad_format(entity, config, fse->pad);
 244
 245        if (fse->index || fse->code != format->code)
 246                return -EINVAL;
 247
 248        if (fse->pad == 0) {
 249                fse->min_width = min_width;
 250                fse->max_width = max_width;
 251                fse->min_height = min_height;
 252                fse->max_height = max_height;
 253        } else {
 254                /* The size on the source pad are fixed and always identical to
 255                 * the size on the sink pad.
 256                 */
 257                fse->min_width = format->width;
 258                fse->max_width = format->width;
 259                fse->min_height = format->height;
 260                fse->max_height = format->height;
 261        }
 262
 263        return 0;
 264}
 265
 266/* -----------------------------------------------------------------------------
 267 * Media Operations
 268 */
 269
 270int vsp1_entity_link_setup(struct media_entity *entity,
 271                           const struct media_pad *local,
 272                           const struct media_pad *remote, u32 flags)
 273{
 274        struct vsp1_entity *source;
 275
 276        if (!(local->flags & MEDIA_PAD_FL_SOURCE))
 277                return 0;
 278
 279        source = media_entity_to_vsp1_entity(local->entity);
 280
 281        if (!source->route)
 282                return 0;
 283
 284        if (flags & MEDIA_LNK_FL_ENABLED) {
 285                if (source->sink)
 286                        return -EBUSY;
 287                source->sink = remote->entity;
 288                source->sink_pad = remote->index;
 289        } else {
 290                source->sink = NULL;
 291                source->sink_pad = 0;
 292        }
 293
 294        return 0;
 295}
 296
 297/* -----------------------------------------------------------------------------
 298 * Initialization
 299 */
 300
 301#define VSP1_ENTITY_ROUTE(ent)                                          \
 302        { VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE,                  \
 303          { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent }
 304
 305#define VSP1_ENTITY_ROUTE_RPF(idx)                                      \
 306        { VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx),                 \
 307          { 0, }, VI6_DPR_NODE_RPF(idx) }
 308
 309#define VSP1_ENTITY_ROUTE_UDS(idx)                                      \
 310        { VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx),                 \
 311          { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) }
 312
 313#define VSP1_ENTITY_ROUTE_WPF(idx)                                      \
 314        { VSP1_ENTITY_WPF, idx, 0,                                      \
 315          { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) }
 316
 317static const struct vsp1_route vsp1_routes[] = {
 318        { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
 319          { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
 320            VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3),
 321            VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT },
 322        VSP1_ENTITY_ROUTE(CLU),
 323        VSP1_ENTITY_ROUTE(HSI),
 324        VSP1_ENTITY_ROUTE(HST),
 325        { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF },
 326        VSP1_ENTITY_ROUTE(LUT),
 327        VSP1_ENTITY_ROUTE_RPF(0),
 328        VSP1_ENTITY_ROUTE_RPF(1),
 329        VSP1_ENTITY_ROUTE_RPF(2),
 330        VSP1_ENTITY_ROUTE_RPF(3),
 331        VSP1_ENTITY_ROUTE_RPF(4),
 332        VSP1_ENTITY_ROUTE(SRU),
 333        VSP1_ENTITY_ROUTE_UDS(0),
 334        VSP1_ENTITY_ROUTE_UDS(1),
 335        VSP1_ENTITY_ROUTE_UDS(2),
 336        VSP1_ENTITY_ROUTE_WPF(0),
 337        VSP1_ENTITY_ROUTE_WPF(1),
 338        VSP1_ENTITY_ROUTE_WPF(2),
 339        VSP1_ENTITY_ROUTE_WPF(3),
 340};
 341
 342int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 343                     const char *name, unsigned int num_pads,
 344                     const struct v4l2_subdev_ops *ops, u32 function)
 345{
 346        struct v4l2_subdev *subdev;
 347        unsigned int i;
 348        int ret;
 349
 350        for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
 351                if (vsp1_routes[i].type == entity->type &&
 352                    vsp1_routes[i].index == entity->index) {
 353                        entity->route = &vsp1_routes[i];
 354                        break;
 355                }
 356        }
 357
 358        if (i == ARRAY_SIZE(vsp1_routes))
 359                return -EINVAL;
 360
 361        entity->vsp1 = vsp1;
 362        entity->source_pad = num_pads - 1;
 363
 364        /* Allocate and initialize pads. */
 365        entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
 366                                    GFP_KERNEL);
 367        if (entity->pads == NULL)
 368                return -ENOMEM;
 369
 370        for (i = 0; i < num_pads - 1; ++i)
 371                entity->pads[i].flags = MEDIA_PAD_FL_SINK;
 372
 373        entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
 374
 375        /* Initialize the media entity. */
 376        ret = media_entity_pads_init(&entity->subdev.entity, num_pads,
 377                                     entity->pads);
 378        if (ret < 0)
 379                return ret;
 380
 381        /* Initialize the V4L2 subdev. */
 382        subdev = &entity->subdev;
 383        v4l2_subdev_init(subdev, ops);
 384
 385        subdev->entity.function = function;
 386        subdev->entity.ops = &vsp1->media_ops;
 387        subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 388
 389        snprintf(subdev->name, sizeof(subdev->name), "%s %s",
 390                 dev_name(vsp1->dev), name);
 391
 392        vsp1_entity_init_cfg(subdev, NULL);
 393
 394        /* Allocate the pad configuration to store formats and selection
 395         * rectangles.
 396         */
 397        entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
 398        if (entity->config == NULL) {
 399                media_entity_cleanup(&entity->subdev.entity);
 400                return -ENOMEM;
 401        }
 402
 403        return 0;
 404}
 405
 406void vsp1_entity_destroy(struct vsp1_entity *entity)
 407{
 408        if (entity->ops && entity->ops->destroy)
 409                entity->ops->destroy(entity);
 410        if (entity->subdev.ctrl_handler)
 411                v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 412        v4l2_subdev_free_pad_config(entity->config);
 413        media_entity_cleanup(&entity->subdev.entity);
 414}
 415