linux/drivers/media/platform/vsp1/vsp1_rwpf.c
<<
>>
Prefs
   1/*
   2 * vsp1_rwpf.c  --  R-Car VSP1 Read and Write Pixel Formatters
   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 <media/v4l2-subdev.h>
  15
  16#include "vsp1.h"
  17#include "vsp1_rwpf.h"
  18#include "vsp1_video.h"
  19
  20#define RWPF_MIN_WIDTH                          1
  21#define RWPF_MIN_HEIGHT                         1
  22
  23/* -----------------------------------------------------------------------------
  24 * V4L2 Subdevice Pad Operations
  25 */
  26
  27int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
  28                             struct v4l2_subdev_fh *fh,
  29                             struct v4l2_subdev_mbus_code_enum *code)
  30{
  31        static const unsigned int codes[] = {
  32                V4L2_MBUS_FMT_ARGB8888_1X32,
  33                V4L2_MBUS_FMT_AYUV8_1X32,
  34        };
  35
  36        if (code->index >= ARRAY_SIZE(codes))
  37                return -EINVAL;
  38
  39        code->code = codes[code->index];
  40
  41        return 0;
  42}
  43
  44int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
  45                              struct v4l2_subdev_fh *fh,
  46                              struct v4l2_subdev_frame_size_enum *fse)
  47{
  48        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
  49        struct v4l2_mbus_framefmt *format;
  50
  51        format = v4l2_subdev_get_try_format(fh, fse->pad);
  52
  53        if (fse->index || fse->code != format->code)
  54                return -EINVAL;
  55
  56        if (fse->pad == RWPF_PAD_SINK) {
  57                fse->min_width = RWPF_MIN_WIDTH;
  58                fse->max_width = rwpf->max_width;
  59                fse->min_height = RWPF_MIN_HEIGHT;
  60                fse->max_height = rwpf->max_height;
  61        } else {
  62                /* The size on the source pad are fixed and always identical to
  63                 * the size on the sink pad.
  64                 */
  65                fse->min_width = format->width;
  66                fse->max_width = format->width;
  67                fse->min_height = format->height;
  68                fse->max_height = format->height;
  69        }
  70
  71        return 0;
  72}
  73
  74static struct v4l2_rect *
  75vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
  76{
  77        switch (which) {
  78        case V4L2_SUBDEV_FORMAT_TRY:
  79                return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK);
  80        case V4L2_SUBDEV_FORMAT_ACTIVE:
  81                return &rwpf->crop;
  82        default:
  83                return NULL;
  84        }
  85}
  86
  87int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
  88                         struct v4l2_subdev_format *fmt)
  89{
  90        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
  91
  92        fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
  93                                                  fmt->which);
  94
  95        return 0;
  96}
  97
  98int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
  99                         struct v4l2_subdev_format *fmt)
 100{
 101        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 102        struct v4l2_mbus_framefmt *format;
 103        struct v4l2_rect *crop;
 104
 105        /* Default to YUV if the requested format is not supported. */
 106        if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
 107            fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
 108                fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
 109
 110        format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
 111                                            fmt->which);
 112
 113        if (fmt->pad == RWPF_PAD_SOURCE) {
 114                /* The RWPF performs format conversion but can't scale, only the
 115                 * format code can be changed on the source pad.
 116                 */
 117                format->code = fmt->format.code;
 118                fmt->format = *format;
 119                return 0;
 120        }
 121
 122        format->code = fmt->format.code;
 123        format->width = clamp_t(unsigned int, fmt->format.width,
 124                                RWPF_MIN_WIDTH, rwpf->max_width);
 125        format->height = clamp_t(unsigned int, fmt->format.height,
 126                                 RWPF_MIN_HEIGHT, rwpf->max_height);
 127        format->field = V4L2_FIELD_NONE;
 128        format->colorspace = V4L2_COLORSPACE_SRGB;
 129
 130        fmt->format = *format;
 131
 132        /* Update the sink crop rectangle. */
 133        crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which);
 134        crop->left = 0;
 135        crop->top = 0;
 136        crop->width = fmt->format.width;
 137        crop->height = fmt->format.height;
 138
 139        /* Propagate the format to the source pad. */
 140        format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
 141                                            fmt->which);
 142        *format = fmt->format;
 143
 144        return 0;
 145}
 146
 147int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 148                            struct v4l2_subdev_fh *fh,
 149                            struct v4l2_subdev_selection *sel)
 150{
 151        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 152        struct v4l2_mbus_framefmt *format;
 153
 154        /* Cropping is implemented on the sink pad. */
 155        if (sel->pad != RWPF_PAD_SINK)
 156                return -EINVAL;
 157
 158        switch (sel->target) {
 159        case V4L2_SEL_TGT_CROP:
 160                sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which);
 161                break;
 162
 163        case V4L2_SEL_TGT_CROP_BOUNDS:
 164                format = vsp1_entity_get_pad_format(&rwpf->entity, fh,
 165                                                    RWPF_PAD_SINK, sel->which);
 166                sel->r.left = 0;
 167                sel->r.top = 0;
 168                sel->r.width = format->width;
 169                sel->r.height = format->height;
 170                break;
 171
 172        default:
 173                return -EINVAL;
 174        }
 175
 176        return 0;
 177}
 178
 179int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 180                            struct v4l2_subdev_fh *fh,
 181                            struct v4l2_subdev_selection *sel)
 182{
 183        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 184        struct v4l2_mbus_framefmt *format;
 185        struct v4l2_rect *crop;
 186
 187        /* Cropping is implemented on the sink pad. */
 188        if (sel->pad != RWPF_PAD_SINK)
 189                return -EINVAL;
 190
 191        if (sel->target != V4L2_SEL_TGT_CROP)
 192                return -EINVAL;
 193
 194        /* Make sure the crop rectangle is entirely contained in the image. The
 195         * WPF top and left offsets are limited to 255.
 196         */
 197        format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK,
 198                                            sel->which);
 199        sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
 200        sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
 201        if (rwpf->entity.type == VSP1_ENTITY_WPF) {
 202                sel->r.left = min_t(unsigned int, sel->r.left, 255);
 203                sel->r.top = min_t(unsigned int, sel->r.top, 255);
 204        }
 205        sel->r.width = min_t(unsigned int, sel->r.width,
 206                             format->width - sel->r.left);
 207        sel->r.height = min_t(unsigned int, sel->r.height,
 208                              format->height - sel->r.top);
 209
 210        crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which);
 211        *crop = sel->r;
 212
 213        /* Propagate the format to the source pad. */
 214        format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
 215                                            sel->which);
 216        format->width = crop->width;
 217        format->height = crop->height;
 218
 219        return 0;
 220}
 221