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_pad_config *cfg,
  29                             struct v4l2_subdev_mbus_code_enum *code)
  30{
  31        static const unsigned int codes[] = {
  32                MEDIA_BUS_FMT_ARGB8888_1X32,
  33                MEDIA_BUS_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_pad_config *cfg,
  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 = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad,
  52                                            fse->which);
  53
  54        if (fse->index || fse->code != format->code)
  55                return -EINVAL;
  56
  57        if (fse->pad == RWPF_PAD_SINK) {
  58                fse->min_width = RWPF_MIN_WIDTH;
  59                fse->max_width = rwpf->max_width;
  60                fse->min_height = RWPF_MIN_HEIGHT;
  61                fse->max_height = rwpf->max_height;
  62        } else {
  63                /* The size on the source pad are fixed and always identical to
  64                 * the size on the sink pad.
  65                 */
  66                fse->min_width = format->width;
  67                fse->max_width = format->width;
  68                fse->min_height = format->height;
  69                fse->max_height = format->height;
  70        }
  71
  72        return 0;
  73}
  74
  75static struct v4l2_rect *
  76vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which)
  77{
  78        switch (which) {
  79        case V4L2_SUBDEV_FORMAT_TRY:
  80                return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK);
  81        case V4L2_SUBDEV_FORMAT_ACTIVE:
  82                return &rwpf->crop;
  83        default:
  84                return NULL;
  85        }
  86}
  87
  88int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
  89                         struct v4l2_subdev_format *fmt)
  90{
  91        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
  92
  93        fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
  94                                                  fmt->which);
  95
  96        return 0;
  97}
  98
  99int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
 100                         struct v4l2_subdev_format *fmt)
 101{
 102        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 103        struct v4l2_mbus_framefmt *format;
 104        struct v4l2_rect *crop;
 105
 106        /* Default to YUV if the requested format is not supported. */
 107        if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 108            fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 109                fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 110
 111        format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
 112                                            fmt->which);
 113
 114        if (fmt->pad == RWPF_PAD_SOURCE) {
 115                /* The RWPF performs format conversion but can't scale, only the
 116                 * format code can be changed on the source pad.
 117                 */
 118                format->code = fmt->format.code;
 119                fmt->format = *format;
 120                return 0;
 121        }
 122
 123        format->code = fmt->format.code;
 124        format->width = clamp_t(unsigned int, fmt->format.width,
 125                                RWPF_MIN_WIDTH, rwpf->max_width);
 126        format->height = clamp_t(unsigned int, fmt->format.height,
 127                                 RWPF_MIN_HEIGHT, rwpf->max_height);
 128        format->field = V4L2_FIELD_NONE;
 129        format->colorspace = V4L2_COLORSPACE_SRGB;
 130
 131        fmt->format = *format;
 132
 133        /* Update the sink crop rectangle. */
 134        crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which);
 135        crop->left = 0;
 136        crop->top = 0;
 137        crop->width = fmt->format.width;
 138        crop->height = fmt->format.height;
 139
 140        /* Propagate the format to the source pad. */
 141        format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
 142                                            fmt->which);
 143        *format = fmt->format;
 144
 145        return 0;
 146}
 147
 148int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 149                            struct v4l2_subdev_pad_config *cfg,
 150                            struct v4l2_subdev_selection *sel)
 151{
 152        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 153        struct v4l2_mbus_framefmt *format;
 154
 155        /* Cropping is implemented on the sink pad. */
 156        if (sel->pad != RWPF_PAD_SINK)
 157                return -EINVAL;
 158
 159        switch (sel->target) {
 160        case V4L2_SEL_TGT_CROP:
 161                sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
 162                break;
 163
 164        case V4L2_SEL_TGT_CROP_BOUNDS:
 165                format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
 166                                                    RWPF_PAD_SINK, sel->which);
 167                sel->r.left = 0;
 168                sel->r.top = 0;
 169                sel->r.width = format->width;
 170                sel->r.height = format->height;
 171                break;
 172
 173        default:
 174                return -EINVAL;
 175        }
 176
 177        return 0;
 178}
 179
 180int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 181                            struct v4l2_subdev_pad_config *cfg,
 182                            struct v4l2_subdev_selection *sel)
 183{
 184        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 185        struct v4l2_mbus_framefmt *format;
 186        struct v4l2_rect *crop;
 187
 188        /* Cropping is implemented on the sink pad. */
 189        if (sel->pad != RWPF_PAD_SINK)
 190                return -EINVAL;
 191
 192        if (sel->target != V4L2_SEL_TGT_CROP)
 193                return -EINVAL;
 194
 195        /* Make sure the crop rectangle is entirely contained in the image. The
 196         * WPF top and left offsets are limited to 255.
 197         */
 198        format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK,
 199                                            sel->which);
 200
 201        /* Restrict the crop rectangle coordinates to multiples of 2 to avoid
 202         * shifting the color plane.
 203         */
 204        if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) {
 205                sel->r.left = ALIGN(sel->r.left, 2);
 206                sel->r.top = ALIGN(sel->r.top, 2);
 207                sel->r.width = round_down(sel->r.width, 2);
 208                sel->r.height = round_down(sel->r.height, 2);
 209        }
 210
 211        sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
 212        sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
 213        if (rwpf->entity.type == VSP1_ENTITY_WPF) {
 214                sel->r.left = min_t(unsigned int, sel->r.left, 255);
 215                sel->r.top = min_t(unsigned int, sel->r.top, 255);
 216        }
 217        sel->r.width = min_t(unsigned int, sel->r.width,
 218                             format->width - sel->r.left);
 219        sel->r.height = min_t(unsigned int, sel->r.height,
 220                              format->height - sel->r.top);
 221
 222        crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
 223        *crop = sel->r;
 224
 225        /* Propagate the format to the source pad. */
 226        format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
 227                                            sel->which);
 228        format->width = crop->width;
 229        format->height = crop->height;
 230
 231        return 0;
 232}
 233