177 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * vsp1_hsit.c -- R-Car VSP1 Hue Saturation value (Inverse) Transform4 *5 * Copyright (C) 2013 Renesas Corporation6 *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 4U20#define HSIT_MAX_SIZE 8190U21 22/* -----------------------------------------------------------------------------23 * Device Access24 */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 Operations34 */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 else49 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 *state;70 struct v4l2_mbus_framefmt *format;71 int ret = 0;72 73 mutex_lock(&hsit->entity.lock);74 75 state = vsp1_entity_get_state(&hsit->entity, sd_state, fmt->which);76 if (!state) {77 ret = -EINVAL;78 goto done;79 }80 81 format = v4l2_subdev_state_get_format(state, fmt->pad);82 83 if (fmt->pad == HSIT_PAD_SOURCE) {84 /*85 * The HST and HSI output format code and resolution can't be86 * modified.87 */88 fmt->format = *format;89 goto done;90 }91 92 format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X3293 : MEDIA_BUS_FMT_ARGB8888_1X32;94 format->width = clamp_t(unsigned int, fmt->format.width,95 HSIT_MIN_SIZE, HSIT_MAX_SIZE);96 format->height = clamp_t(unsigned int, fmt->format.height,97 HSIT_MIN_SIZE, HSIT_MAX_SIZE);98 format->field = V4L2_FIELD_NONE;99 format->colorspace = V4L2_COLORSPACE_SRGB;100 101 fmt->format = *format;102 103 /* Propagate the format to the source pad. */104 format = v4l2_subdev_state_get_format(state, HSIT_PAD_SOURCE);105 *format = fmt->format;106 format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32107 : 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 .enum_mbus_code = hsit_enum_mbus_code,116 .enum_frame_size = hsit_enum_frame_size,117 .get_fmt = vsp1_subdev_get_pad_format,118 .set_fmt = hsit_set_format,119};120 121static const struct v4l2_subdev_ops hsit_ops = {122 .pad = &hsit_pad_ops,123};124 125/* -----------------------------------------------------------------------------126 * VSP1 Entity Operations127 */128 129static void hsit_configure_stream(struct vsp1_entity *entity,130 struct v4l2_subdev_state *state,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 else140 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 Cleanup149 */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 else167 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