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_state *sd_state,
  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_state *sd_state,
  56                                struct v4l2_subdev_frame_size_enum *fse)
  57{
  58        return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
  59                                           HSIT_MIN_SIZE,
  60                                           HSIT_MIN_SIZE, HSIT_MAX_SIZE,
  61                                           HSIT_MAX_SIZE);
  62}
  63
  64static int hsit_set_format(struct v4l2_subdev *subdev,
  65                           struct v4l2_subdev_state *sd_state,
  66                           struct v4l2_subdev_format *fmt)
  67{
  68        struct vsp1_hsit *hsit = to_hsit(subdev);
  69        struct v4l2_subdev_state *config;
  70        struct v4l2_mbus_framefmt *format;
  71        int ret = 0;
  72
  73        mutex_lock(&hsit->entity.lock);
  74
  75        config = vsp1_entity_get_pad_config(&hsit->entity, sd_state,
  76                                            fmt->which);
  77        if (!config) {
  78                ret = -EINVAL;
  79                goto done;
  80        }
  81
  82        format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
  83
  84        if (fmt->pad == HSIT_PAD_SOURCE) {
  85                /*
  86                 * The HST and HSI output format code and resolution can't be
  87                 * modified.
  88                 */
  89                fmt->format = *format;
  90                goto done;
  91        }
  92
  93        format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32
  94                     : MEDIA_BUS_FMT_ARGB8888_1X32;
  95        format->width = clamp_t(unsigned int, fmt->format.width,
  96                                HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  97        format->height = clamp_t(unsigned int, fmt->format.height,
  98                                 HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  99        format->field = V4L2_FIELD_NONE;
 100        format->colorspace = V4L2_COLORSPACE_SRGB;
 101
 102        fmt->format = *format;
 103
 104        /* Propagate the format to the source pad. */
 105        format = vsp1_entity_get_pad_format(&hsit->entity, config,
 106                                            HSIT_PAD_SOURCE);
 107        *format = fmt->format;
 108        format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
 109                     : MEDIA_BUS_FMT_AHSV8888_1X32;
 110
 111done:
 112        mutex_unlock(&hsit->entity.lock);
 113        return ret;
 114}
 115
 116static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
 117        .init_cfg = vsp1_entity_init_cfg,
 118        .enum_mbus_code = hsit_enum_mbus_code,
 119        .enum_frame_size = hsit_enum_frame_size,
 120        .get_fmt = vsp1_subdev_get_pad_format,
 121        .set_fmt = hsit_set_format,
 122};
 123
 124static const struct v4l2_subdev_ops hsit_ops = {
 125        .pad    = &hsit_pad_ops,
 126};
 127
 128/* -----------------------------------------------------------------------------
 129 * VSP1 Entity Operations
 130 */
 131
 132static void hsit_configure_stream(struct vsp1_entity *entity,
 133                                  struct vsp1_pipeline *pipe,
 134                                  struct vsp1_dl_list *dl,
 135                                  struct vsp1_dl_body *dlb)
 136{
 137        struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 138
 139        if (hsit->inverse)
 140                vsp1_hsit_write(hsit, dlb, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
 141        else
 142                vsp1_hsit_write(hsit, dlb, VI6_HST_CTRL, VI6_HST_CTRL_EN);
 143}
 144
 145static const struct vsp1_entity_operations hsit_entity_ops = {
 146        .configure_stream = hsit_configure_stream,
 147};
 148
 149/* -----------------------------------------------------------------------------
 150 * Initialization and Cleanup
 151 */
 152
 153struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 154{
 155        struct vsp1_hsit *hsit;
 156        int ret;
 157
 158        hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
 159        if (hsit == NULL)
 160                return ERR_PTR(-ENOMEM);
 161
 162        hsit->inverse = inverse;
 163
 164        hsit->entity.ops = &hsit_entity_ops;
 165
 166        if (inverse)
 167                hsit->entity.type = VSP1_ENTITY_HSI;
 168        else
 169                hsit->entity.type = VSP1_ENTITY_HST;
 170
 171        ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst",
 172                               2, &hsit_ops,
 173                               MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV);
 174        if (ret < 0)
 175                return ERR_PTR(ret);
 176
 177        return hsit;
 178}
 179