File Index
Files and directories
Sign in
FILE

vsp1_rwpf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * vsp1_rwpf.c  --  R-Car VSP1 Read and Write Pixel Formatters
  4 *
  5 * Copyright (C) 2013-2014 Renesas Electronics Corporation
  6 *
  7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  8 */
  9
 10#include <media/v4l2-subdev.h>
 11
 12#include "vsp1.h"
 13#include "vsp1_entity.h"
 14#include "vsp1_rwpf.h"
 15#include "vsp1_video.h"
 16
 17#define RWPF_MIN_WIDTH				1
 18#define RWPF_MIN_HEIGHT				1
 19
 20/* -----------------------------------------------------------------------------
 21 * V4L2 Subdevice Operations
 22 */
 23
 24static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 25				    struct v4l2_subdev_state *sd_state,
 26				    struct v4l2_subdev_mbus_code_enum *code)
 27{
 28	static const unsigned int codes[] = {
 29		MEDIA_BUS_FMT_ARGB8888_1X32,
 30		MEDIA_BUS_FMT_AHSV8888_1X32,
 31		MEDIA_BUS_FMT_AYUV8_1X32,
 32	};
 33
 34	if (code->index >= ARRAY_SIZE(codes))
 35		return -EINVAL;
 36
 37	code->code = codes[code->index];
 38
 39	if (code->pad == RWPF_PAD_SOURCE &&
 40	    code->code == MEDIA_BUS_FMT_AYUV8_1X32)
 41		code->flags = V4L2_SUBDEV_MBUS_CODE_CSC_YCBCR_ENC
 42			    | V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION;
 43
 44	return 0;
 45}
 46
 47static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 48				     struct v4l2_subdev_state *sd_state,
 49				     struct v4l2_subdev_frame_size_enum *fse)
 50{
 51	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 52
 53	return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
 54					   RWPF_MIN_WIDTH,
 55					   RWPF_MIN_HEIGHT, rwpf->max_width,
 56					   rwpf->max_height);
 57}
 58
 59static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 60				struct v4l2_subdev_state *sd_state,
 61				struct v4l2_subdev_format *fmt)
 62{
 63	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 64	struct v4l2_subdev_state *state;
 65	struct v4l2_mbus_framefmt *format;
 66	int ret = 0;
 67
 68	mutex_lock(&rwpf->entity.lock);
 69
 70	state = vsp1_entity_get_state(&rwpf->entity, sd_state, fmt->which);
 71	if (!state) {
 72		ret = -EINVAL;
 73		goto done;
 74	}
 75
 76	/* Default to YUV if the requested format is not supported. */
 77	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 78	    fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
 79	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 80		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 81
 82	format = v4l2_subdev_state_get_format(state, fmt->pad);
 83
 84	if (fmt->pad == RWPF_PAD_SOURCE) {
 85		const struct v4l2_mbus_framefmt *sink_format =
 86			v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
 87		u16 flags = fmt->format.flags & V4L2_MBUS_FRAMEFMT_SET_CSC;
 88		bool csc;
 89
 90		/*
 91		 * The RWPF performs format conversion but can't scale, only the
 92		 * format code, encoding and quantization can be changed on the
 93		 * source pad when converting between RGB and YUV.
 94		 */
 95		if (sink_format->code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
 96		    fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32)
 97			format->code = fmt->format.code;
 98		else
 99			format->code = sink_format->code;
100
101		/*
102		 * Encoding and quantization can only be configured when YCbCr
103		 * <-> RGB is enabled. The V4L2 API requires userspace to set
104		 * the V4L2_MBUS_FRAMEFMT_SET_CSC flag. If either of these
105		 * conditions is not met, use the encoding and quantization
106		 * values from the sink pad.
107		 */
108		csc = (format->code == MEDIA_BUS_FMT_AYUV8_1X32) !=
109		      (sink_format->code == MEDIA_BUS_FMT_AYUV8_1X32);
110
111		if (csc && (flags & V4L2_MBUS_FRAMEFMT_SET_CSC)) {
112			format->ycbcr_enc = fmt->format.ycbcr_enc;
113			format->quantization = fmt->format.quantization;
114		} else {
115			format->ycbcr_enc = sink_format->ycbcr_enc;
116			format->quantization = sink_format->quantization;
117		}
118
119		vsp1_entity_adjust_color_space(format);
120
121		fmt->format = *format;
122		fmt->format.flags = flags;
123
124		goto done;
125	}
126
127	format->code = fmt->format.code;
128	format->width = clamp_t(unsigned int, fmt->format.width,
129				RWPF_MIN_WIDTH, rwpf->max_width);
130	format->height = clamp_t(unsigned int, fmt->format.height,
131				 RWPF_MIN_HEIGHT, rwpf->max_height);
132	format->field = V4L2_FIELD_NONE;
133
134	format->colorspace = fmt->format.colorspace;
135	format->xfer_func = fmt->format.xfer_func;
136	format->ycbcr_enc = fmt->format.ycbcr_enc;
137	format->quantization = fmt->format.quantization;
138
139	vsp1_entity_adjust_color_space(format);
140
141	fmt->format = *format;
142
143	if (rwpf->entity.type == VSP1_ENTITY_RPF) {
144		struct v4l2_rect *crop;
145
146		/* Update the sink crop rectangle. */
147		crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
148		crop->left = 0;
149		crop->top = 0;
150		crop->width = fmt->format.width;
151		crop->height = fmt->format.height;
152	}
153
154	/* Propagate the format to the source pad. */
155	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
156	*format = fmt->format;
157
158	if (rwpf->flip.rotate) {
159		format->width = fmt->format.height;
160		format->height = fmt->format.width;
161	}
162
163done:
164	mutex_unlock(&rwpf->entity.lock);
165	return ret;
166}
167
168static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
169				   struct v4l2_subdev_state *sd_state,
170				   struct v4l2_subdev_selection *sel)
171{
172	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
173	struct v4l2_subdev_state *state;
174	struct v4l2_mbus_framefmt *format;
175	int ret = 0;
176
177	/*
178	 * Cropping is only supported on the RPF and is implemented on the sink
179	 * pad.
180	 */
181	if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK)
182		return -EINVAL;
183
184	mutex_lock(&rwpf->entity.lock);
185
186	state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);
187	if (!state) {
188		ret = -EINVAL;
189		goto done;
190	}
191
192	switch (sel->target) {
193	case V4L2_SEL_TGT_CROP:
194		sel->r = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
195		break;
196
197	case V4L2_SEL_TGT_CROP_BOUNDS:
198		format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
199		sel->r.left = 0;
200		sel->r.top = 0;
201		sel->r.width = format->width;
202		sel->r.height = format->height;
203		break;
204
205	default:
206		ret = -EINVAL;
207		break;
208	}
209
210done:
211	mutex_unlock(&rwpf->entity.lock);
212	return ret;
213}
214
215static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
216				   struct v4l2_subdev_state *sd_state,
217				   struct v4l2_subdev_selection *sel)
218{
219	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
220	struct v4l2_subdev_state *state;
221	struct v4l2_mbus_framefmt *format;
222	struct v4l2_rect *crop;
223	int ret = 0;
224
225	/*
226	 * Cropping is only supported on the RPF and is implemented on the sink
227	 * pad.
228	 */
229	if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK)
230		return -EINVAL;
231
232	if (sel->target != V4L2_SEL_TGT_CROP)
233		return -EINVAL;
234
235	mutex_lock(&rwpf->entity.lock);
236
237	state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);
238	if (!state) {
239		ret = -EINVAL;
240		goto done;
241	}
242
243	/* Make sure the crop rectangle is entirely contained in the image. */
244	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
245
246	/*
247	 * Restrict the crop rectangle coordinates to multiples of 2 to avoid
248	 * shifting the color plane.
249	 */
250	if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) {
251		sel->r.left = ALIGN(sel->r.left, 2);
252		sel->r.top = ALIGN(sel->r.top, 2);
253		sel->r.width = round_down(sel->r.width, 2);
254		sel->r.height = round_down(sel->r.height, 2);
255	}
256
257	sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
258	sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
259	sel->r.width = min_t(unsigned int, sel->r.width,
260			     format->width - sel->r.left);
261	sel->r.height = min_t(unsigned int, sel->r.height,
262			      format->height - sel->r.top);
263
264	crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
265	*crop = sel->r;
266
267	/* Propagate the format to the source pad. */
268	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
269	format->width = crop->width;
270	format->height = crop->height;
271
272done:
273	mutex_unlock(&rwpf->entity.lock);
274	return ret;
275}
276
277static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
278	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
279	.enum_frame_size = vsp1_rwpf_enum_frame_size,
280	.get_fmt = vsp1_subdev_get_pad_format,
281	.set_fmt = vsp1_rwpf_set_format,
282	.get_selection = vsp1_rwpf_get_selection,
283	.set_selection = vsp1_rwpf_set_selection,
284};
285
286const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops = {
287	.pad    = &vsp1_rwpf_pad_ops,
288};
289
290/* -----------------------------------------------------------------------------
291 * Controls
292 */
293
294static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)
295{
296	struct vsp1_rwpf *rwpf =
297		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
298
299	switch (ctrl->id) {
300	case V4L2_CID_ALPHA_COMPONENT:
301		rwpf->alpha = ctrl->val;
302		break;
303	}
304
305	return 0;
306}
307
308static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
309	.s_ctrl = vsp1_rwpf_s_ctrl,
310};
311
312int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)
313{
314	v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);
315	v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
316			  V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
317
318	rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;
319
320	return rwpf->ctrls.error;
321}
~/ Read-only file preview.