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 26 static 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 36 static 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 54 static 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 64 static 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 111 done: 112 mutex_unlock(&hsit->entity.lock); 113 return ret; 114 } 115 116 static 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 124 static const struct v4l2_subdev_ops hsit_ops = { 125 .pad = &hsit_pad_ops, 126 }; 127 128 /* ----------------------------------------------------------------------------- 129 * VSP1 Entity Operations 130 */ 131 132 static 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 145 static const struct vsp1_entity_operations hsit_entity_ops = { 146 .configure_stream = hsit_configure_stream, 147 }; 148 149 /* ----------------------------------------------------------------------------- 150 * Initialization and Cleanup 151 */ 152 153 struct 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