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