linux/drivers/media/platform/vsp1/vsp1_hsit.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * vsp1_hsit.c  --  R-Car VSP1 Hue Saturation value (Inverse) Transform
   4 *
   5 * Copyright (C) 2013 Renesas 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/v4l2-subdev.h>
  14
  15#include "vsp1.h"
  16#include "vsp1_dl.h"
  17#include "vsp1_hsit.h"
  18
  19#define HSIT_MIN_SIZE                           4U
  20#define HSIT_MAX_SIZE                           8190U
  21
  22/* -----------------------------------------------------------------------------
  23 * Device Access
  24 */
  25
  26static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
  27                                   struct vsp1_dl_body *dlb, u32 reg, u32 data)
  28{
  29        vsp1_dl_body_write(dlb, reg, data);
  30}
  31
  32/* -----------------------------------------------------------------------------
  33 * V4L2 Subdevice Operations
  34 */
  35
  36static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
  37                               struct v4l2_subdev_pad_config *cfg,
  38                               struct v4l2_subdev_mbus_code_enum *code)
  39{
  40        struct vsp1_hsit *hsit = to_hsit(subdev);
  41
  42        if (code->index > 0)
  43                return -EINVAL;
  44
  45        if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
  46            (code->pad == HSIT_PAD_SOURCE && hsit->inverse))
  47                code->code = MEDIA_BUS_FMT_ARGB8888_1X32;
  48        else
  49                code->code = MEDIA_BUS_FMT_AHSV8888_1X32;
  50
  51        return 0;
  52}
  53
  54static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
  55                                struct v4l2_subdev_pad_config *cfg,
  56                                struct v4l2_subdev_frame_size_enum *fse)
  57{
  58        return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE,
  59                                           HSIT_MIN_SIZE, HSIT_MAX_SIZE,
  60                                           HSIT_MAX_SIZE);
  61}
  62
  63static int hsit_set_format(struct v4l2_subdev *subdev,
  64                           struct v4l2_subdev_pad_config *cfg,
  65                           struct v4l2_subdev_format *fmt)
  66{
  67        struct vsp1_hsit *hsit = to_hsit(subdev);
  68        struct v4l2_subdev_pad_config *config;
  69        struct v4l2_mbus_framefmt *format;
  70        int ret = 0;
  71
  72        mutex_lock(&hsit->entity.lock);
  73
  74        config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
  75        if (!config) {
  76                ret = -EINVAL;
  77                goto done;
  78        }
  79
  80        format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
  81
  82        if (fmt->pad == HSIT_PAD_SOURCE) {
  83                /*
  84                 * The HST and HSI output format code and resolution can't be
  85                 * modified.
  86                 */
  87                fmt->format = *format;
  88                goto done;
  89        }
  90
  91        format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32
  92                     : MEDIA_BUS_FMT_ARGB8888_1X32;
  93        format->width = clamp_t(unsigned int, fmt->format.width,
  94                                HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  95        format->height = clamp_t(unsigned int, fmt->format.height,
  96                                 HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  97        format->field = V4L2_FIELD_NONE;
  98        format->colorspace = V4L2_COLORSPACE_SRGB;
  99
 100        fmt->format = *format;
 101
 102        /* Propagate the format to the source pad. */
 103        format = vsp1_entity_get_pad_format(&hsit->entity, config,
 104                                            HSIT_PAD_SOURCE);
 105        *format = fmt->format;
 106        format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
 107                     : MEDIA_BUS_FMT_AHSV8888_1X32;
 108
 109done:
 110        mutex_unlock(&hsit->entity.lock);
 111        return ret;
 112}
 113
 114static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
 115        .init_cfg = vsp1_entity_init_cfg,
 116        .enum_mbus_code = hsit_enum_mbus_code,
 117        .enum_frame_size = hsit_enum_frame_size,
 118        .get_fmt = vsp1_subdev_get_pad_format,
 119        .set_fmt = hsit_set_format,
 120};
 121
 122static const struct v4l2_subdev_ops hsit_ops = {
 123        .pad    = &hsit_pad_ops,
 124};
 125
 126/* -----------------------------------------------------------------------------
 127 * VSP1 Entity Operations
 128 */
 129
 130static void hsit_configure_stream(struct vsp1_entity *entity,
 131                                  struct vsp1_pipeline *pipe,
 132                                  struct vsp1_dl_list *dl,
 133                                  struct vsp1_dl_body *dlb)
 134{
 135        struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 136
 137        if (hsit->inverse)
 138                vsp1_hsit_write(hsit, dlb, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
 139        else
 140                vsp1_hsit_write(hsit, dlb, VI6_HST_CTRL, VI6_HST_CTRL_EN);
 141}
 142
 143static const struct vsp1_entity_operations hsit_entity_ops = {
 144        .configure_stream = hsit_configure_stream,
 145};
 146
 147/* -----------------------------------------------------------------------------
 148 * Initialization and Cleanup
 149 */
 150
 151struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 152{
 153        struct vsp1_hsit *hsit;
 154        int ret;
 155
 156        hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
 157        if (hsit == NULL)
 158                return ERR_PTR(-ENOMEM);
 159
 160        hsit->inverse = inverse;
 161
 162        hsit->entity.ops = &hsit_entity_ops;
 163
 164        if (inverse)
 165                hsit->entity.type = VSP1_ENTITY_HSI;
 166        else
 167                hsit->entity.type = VSP1_ENTITY_HST;
 168
 169        ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst",
 170                               2, &hsit_ops,
 171                               MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV);
 172        if (ret < 0)
 173                return ERR_PTR(ret);
 174
 175        return hsit;
 176}
 177