File Index
Files and directories
Sign in
FILE

rkisp1-resizer.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c C
  1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  2/*
  3 * Rockchip ISP1 Driver - V4l resizer device
  4 *
  5 * Copyright (C) 2019 Collabora, Ltd.
  6 *
  7 * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
  8 * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
  9 */
 10
 11#include "rkisp1-common.h"
 12
 13#define RKISP1_RSZ_SP_DEV_NAME	RKISP1_DRIVER_NAME "_resizer_selfpath"
 14#define RKISP1_RSZ_MP_DEV_NAME	RKISP1_DRIVER_NAME "_resizer_mainpath"
 15
 16#define RKISP1_DEF_FMT MEDIA_BUS_FMT_YUYV8_2X8
 17#define RKISP1_DEF_PIXEL_ENC V4L2_PIXEL_ENC_YUV
 18
 19struct rkisp1_rsz_yuv_mbus_info {
 20	u32 mbus_code;
 21	u32 hdiv;
 22	u32 vdiv;
 23};
 24
 25static const struct rkisp1_rsz_yuv_mbus_info rkisp1_rsz_yuv_src_formats[] = {
 26	{
 27		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8, /* YUV422 */
 28		.hdiv		= 2,
 29		.vdiv		= 1,
 30	},
 31	{
 32		.mbus_code	= MEDIA_BUS_FMT_YUYV8_1_5X8, /* YUV420 */
 33		.hdiv		= 2,
 34		.vdiv		= 2,
 35	},
 36};
 37
 38static const struct rkisp1_rsz_yuv_mbus_info *rkisp1_rsz_get_yuv_mbus_info(u32 mbus_code)
 39{
 40	unsigned int i;
 41
 42	for (i = 0; i < ARRAY_SIZE(rkisp1_rsz_yuv_src_formats); i++) {
 43		if (rkisp1_rsz_yuv_src_formats[i].mbus_code == mbus_code)
 44			return &rkisp1_rsz_yuv_src_formats[i];
 45	}
 46
 47	return NULL;
 48}
 49
 50enum rkisp1_shadow_regs_when {
 51	RKISP1_SHADOW_REGS_SYNC,
 52	RKISP1_SHADOW_REGS_ASYNC,
 53};
 54
 55struct rkisp1_rsz_config {
 56	/* constrains */
 57	const int max_rsz_width;
 58	const int max_rsz_height;
 59	const int min_rsz_width;
 60	const int min_rsz_height;
 61	/* registers */
 62	struct {
 63		u32 yuvmode_mask;
 64		u32 rawmode_mask;
 65		u32 h_offset;
 66		u32 v_offset;
 67		u32 h_size;
 68		u32 v_size;
 69	} dual_crop;
 70};
 71
 72static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = {
 73	/* constraints */
 74	.max_rsz_width = RKISP1_RSZ_MP_SRC_MAX_WIDTH,
 75	.max_rsz_height = RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
 76	.min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH,
 77	.min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT,
 78	/* registers */
 79	.dual_crop = {
 80		.yuvmode_mask =		RKISP1_CIF_DUAL_CROP_MP_MODE_YUV,
 81		.rawmode_mask =		RKISP1_CIF_DUAL_CROP_MP_MODE_RAW,
 82		.h_offset =		RKISP1_CIF_DUAL_CROP_M_H_OFFS,
 83		.v_offset =		RKISP1_CIF_DUAL_CROP_M_V_OFFS,
 84		.h_size =		RKISP1_CIF_DUAL_CROP_M_H_SIZE,
 85		.v_size =		RKISP1_CIF_DUAL_CROP_M_V_SIZE,
 86	},
 87};
 88
 89static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = {
 90	/* constraints */
 91	.max_rsz_width = RKISP1_RSZ_SP_SRC_MAX_WIDTH,
 92	.max_rsz_height = RKISP1_RSZ_SP_SRC_MAX_HEIGHT,
 93	.min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH,
 94	.min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT,
 95	/* registers */
 96	.dual_crop = {
 97		.yuvmode_mask =		RKISP1_CIF_DUAL_CROP_SP_MODE_YUV,
 98		.rawmode_mask =		RKISP1_CIF_DUAL_CROP_SP_MODE_RAW,
 99		.h_offset =		RKISP1_CIF_DUAL_CROP_S_H_OFFS,
100		.v_offset =		RKISP1_CIF_DUAL_CROP_S_V_OFFS,
101		.h_size =		RKISP1_CIF_DUAL_CROP_S_H_SIZE,
102		.v_size =		RKISP1_CIF_DUAL_CROP_S_V_SIZE,
103	},
104};
105
106static inline u32 rkisp1_rsz_read(struct rkisp1_resizer *rsz, u32 offset)
107{
108	return rkisp1_read(rsz->rkisp1, rsz->regs_base + offset);
109}
110
111static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset,
112				    u32 value)
113{
114	rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value);
115}
116
117/* ----------------------------------------------------------------------------
118 * Dual crop hw configs
119 */
120
121static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz,
122				 enum rkisp1_shadow_regs_when when)
123{
124	u32 dc_ctrl = rkisp1_read(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL);
125	u32 mask = ~(rsz->config->dual_crop.yuvmode_mask |
126		     rsz->config->dual_crop.rawmode_mask);
127
128	dc_ctrl &= mask;
129	if (when == RKISP1_SHADOW_REGS_ASYNC)
130		dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD;
131	else
132		dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD;
133	rkisp1_write(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl);
134}
135
136/* configure dual-crop unit */
137static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz,
138				const struct v4l2_subdev_state *sd_state)
139{
140	struct rkisp1_device *rkisp1 = rsz->rkisp1;
141	const struct v4l2_mbus_framefmt *sink_fmt;
142	const struct v4l2_rect *sink_crop;
143	u32 dc_ctrl;
144
145	sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
146	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
147
148	if (sink_crop->width == sink_fmt->width &&
149	    sink_crop->height == sink_fmt->height &&
150	    sink_crop->left == 0 && sink_crop->top == 0) {
151		rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_SYNC);
152		dev_dbg(rkisp1->dev, "capture %d crop disabled\n", rsz->id);
153		return;
154	}
155
156	dc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL);
157	rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left);
158	rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top);
159	rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width);
160	rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height);
161	dc_ctrl |= rsz->config->dual_crop.yuvmode_mask;
162	dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD;
163	rkisp1_write(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl);
164
165	dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id,
166		sink_fmt->width, sink_fmt->height,
167		sink_crop->width, sink_crop->height);
168}
169
170/* ----------------------------------------------------------------------------
171 * Resizer hw configs
172 */
173
174static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz,
175				     enum rkisp1_shadow_regs_when when)
176{
177	u32 ctrl_cfg = rkisp1_rsz_read(rsz, RKISP1_CIF_RSZ_CTRL);
178
179	if (when == RKISP1_SHADOW_REGS_ASYNC)
180		ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO;
181	else
182		ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD;
183
184	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, ctrl_cfg);
185}
186
187static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src)
188{
189	if (len_sink < len_src)
190		return ((len_sink - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) /
191		       (len_src - 1);
192
193	return ((len_src - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) /
194	       (len_sink - 1) + 1;
195}
196
197static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz,
198			       enum rkisp1_shadow_regs_when when)
199{
200	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, 0);
201
202	if (when == RKISP1_SHADOW_REGS_SYNC)
203		rkisp1_rsz_update_shadow(rsz, when);
204}
205
206static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
207				   const struct v4l2_rect *sink_y,
208				   const struct v4l2_rect *sink_c,
209				   const struct v4l2_area *src_y,
210				   const struct v4l2_area *src_c,
211				   enum rkisp1_shadow_regs_when when)
212{
213	u32 ratio, rsz_ctrl = 0;
214	unsigned int i;
215
216	/* No phase offset */
217	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HY, 0);
218	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HC, 0);
219	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VY, 0);
220	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VC, 0);
221
222	/* Linear interpolation */
223	for (i = 0; i < 64; i++) {
224		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT_ADDR, i);
225		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT, i);
226	}
227
228	if (sink_y->width != src_y->width) {
229		rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE;
230		if (sink_y->width < src_y->width)
231			rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP;
232		ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width);
233		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HY, ratio);
234	}
235
236	if (sink_c->width != src_c->width) {
237		rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE;
238		if (sink_c->width < src_c->width)
239			rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP;
240		ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width);
241		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCB, ratio);
242		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCR, ratio);
243	}
244
245	if (sink_y->height != src_y->height) {
246		rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE;
247		if (sink_y->height < src_y->height)
248			rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP;
249		ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height);
250		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VY, ratio);
251	}
252
253	if (sink_c->height != src_c->height) {
254		rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE;
255		if (sink_c->height < src_c->height)
256			rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP;
257		ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height);
258		rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VC, ratio);
259	}
260
261	rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, rsz_ctrl);
262
263	rkisp1_rsz_update_shadow(rsz, when);
264}
265
266static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
267			      const struct v4l2_subdev_state *sd_state,
268			      enum rkisp1_shadow_regs_when when)
269{
270	const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info;
271	const struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
272	const struct v4l2_rect *sink_y;
273	struct v4l2_area src_y, src_c;
274	struct v4l2_rect sink_c;
275
276	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
277	src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
278
279	sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code);
280	src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code);
281
282	/*
283	 * The resizer only works on yuv formats, so return if it is bayer
284	 * format.
285	 */
286	if (!sink_yuv_info) {
287		rkisp1_rsz_disable(rsz, when);
288		return;
289	}
290
291	sink_y = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
292	sink_c.width = sink_y->width / sink_yuv_info->hdiv;
293	sink_c.height = sink_y->height / sink_yuv_info->vdiv;
294
295	src_y.width = src_fmt->width;
296	src_y.height = src_fmt->height;
297	src_c.width = src_y.width / src_yuv_info->hdiv;
298	src_c.height = src_y.height / src_yuv_info->vdiv;
299
300	/*
301	 * The resizer is used not only to change the dimensions of the frame
302	 * but also to change the subsampling for YUV formats (for instance
303	 * converting from 4:2:2 to 4:2:0). Check both the luma and chroma
304	 * dimensions to decide whether or not to enable the resizer.
305	 */
306
307	dev_dbg(rsz->rkisp1->dev,
308		"stream %u rsz/scale: Y %ux%u -> %ux%u, CbCr %ux%u -> %ux%u\n",
309		rsz->id, sink_y->width, sink_y->height,
310		src_fmt->width, src_fmt->height,
311		sink_c.width, sink_c.height, src_c.width, src_c.height);
312
313	if (sink_y->width == src_y.width && sink_y->height == src_y.height &&
314	    sink_c.width == src_c.width && sink_c.height == src_c.height) {
315		rkisp1_rsz_disable(rsz, when);
316		return;
317	}
318
319	/* Set values in the hardware. */
320	rkisp1_rsz_config_regs(rsz, sink_y, &sink_c, &src_y, &src_c, when);
321}
322
323/* ----------------------------------------------------------------------------
324 * Subdev pad operations
325 */
326
327static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
328				     struct v4l2_subdev_state *sd_state,
329				     struct v4l2_subdev_mbus_code_enum *code)
330{
331	struct rkisp1_resizer *rsz =
332		container_of(sd, struct rkisp1_resizer, sd);
333	unsigned int index = code->index;
334	unsigned int i;
335
336	if (code->pad == RKISP1_RSZ_PAD_SRC) {
337		/* supported mbus codes on the src are the same as in the capture */
338		struct rkisp1_capture *cap = &rsz->rkisp1->capture_devs[rsz->id];
339
340		return rkisp1_cap_enum_mbus_codes(cap, code);
341	}
342
343	/*
344	 * The selfpath capture doesn't support bayer formats. Therefore the selfpath resizer
345	 * should support only YUV422 on the sink pad
346	 */
347	if (rsz->id == RKISP1_SELFPATH) {
348		if (code->index > 0)
349			return -EINVAL;
350		code->code = MEDIA_BUS_FMT_YUYV8_2X8;
351		return 0;
352	}
353
354	/*
355	 * Supported mbus codes on the sink pad are the same as on the ISP
356	 * source pad.
357	 */
358	for (i = 0; ; i++) {
359		const struct rkisp1_mbus_info *fmt =
360			rkisp1_mbus_info_get_by_index(i);
361
362		if (!fmt)
363			break;
364
365		if (!(fmt->direction & RKISP1_ISP_SD_SRC))
366			continue;
367
368		if (!index) {
369			code->code = fmt->mbus_code;
370			return 0;
371		}
372
373		index--;
374	}
375
376	return -EINVAL;
377}
378
379static int rkisp1_rsz_init_state(struct v4l2_subdev *sd,
380				 struct v4l2_subdev_state *sd_state)
381{
382	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
383	struct v4l2_rect *sink_crop;
384
385	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
386	sink_fmt->width = RKISP1_DEFAULT_WIDTH;
387	sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
388	sink_fmt->field = V4L2_FIELD_NONE;
389	sink_fmt->code = RKISP1_DEF_FMT;
390	sink_fmt->colorspace = V4L2_COLORSPACE_SRGB;
391	sink_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
392	sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
393	sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
394
395	sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
396	sink_crop->width = RKISP1_DEFAULT_WIDTH;
397	sink_crop->height = RKISP1_DEFAULT_HEIGHT;
398	sink_crop->left = 0;
399	sink_crop->top = 0;
400
401	src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
402	*src_fmt = *sink_fmt;
403
404	/* NOTE: there is no crop in the source pad, only in the sink */
405
406	return 0;
407}
408
409static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
410				   struct v4l2_subdev_state *sd_state,
411				   struct v4l2_mbus_framefmt *format)
412{
413	const struct rkisp1_mbus_info *sink_mbus_info;
414	struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
415
416	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
417	src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
418
419	sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
420
421	/* for YUV formats, userspace can change the mbus code on the src pad if it is supported */
422	if (sink_mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV &&
423	    rkisp1_rsz_get_yuv_mbus_info(format->code))
424		src_fmt->code = format->code;
425
426	src_fmt->width = clamp_t(u32, format->width,
427				 rsz->config->min_rsz_width,
428				 rsz->config->max_rsz_width);
429	src_fmt->height = clamp_t(u32, format->height,
430				  rsz->config->min_rsz_height,
431				  rsz->config->max_rsz_height);
432
433	*format = *src_fmt;
434}
435
436static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
437				     struct v4l2_subdev_state *sd_state,
438				     struct v4l2_rect *r)
439{
440	const struct rkisp1_mbus_info *mbus_info;
441	struct v4l2_mbus_framefmt *sink_fmt;
442	struct v4l2_rect *sink_crop;
443
444	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
445	sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
446
447	/* Not crop for MP bayer raw data, or for devices lacking dual crop. */
448	mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
449
450	if ((rsz->id == RKISP1_MAINPATH &&
451	     mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) ||
452	    !rkisp1_has_feature(rsz->rkisp1, DUAL_CROP)) {
453		sink_crop->left = 0;
454		sink_crop->top = 0;
455		sink_crop->width = sink_fmt->width;
456		sink_crop->height = sink_fmt->height;
457
458		*r = *sink_crop;
459		return;
460	}
461
462	sink_crop->left = ALIGN(r->left, 2);
463	sink_crop->width = ALIGN(r->width, 2);
464	sink_crop->top = r->top;
465	sink_crop->height = r->height;
466	rkisp1_sd_adjust_crop(sink_crop, sink_fmt);
467
468	*r = *sink_crop;
469}
470
471static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
472				    struct v4l2_subdev_state *sd_state,
473				    struct v4l2_mbus_framefmt *format)
474{
475	const struct rkisp1_mbus_info *mbus_info;
476	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
477	struct v4l2_rect *sink_crop;
478	bool is_yuv;
479
480	sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
481	src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
482	sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
483
484	if (rsz->id == RKISP1_SELFPATH)
485		sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
486	else
487		sink_fmt->code = format->code;
488
489	mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
490	if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) {
491		sink_fmt->code = RKISP1_DEF_FMT;
492		mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
493	}
494
495	sink_fmt->width = clamp_t(u32, format->width,
496				  RKISP1_ISP_MIN_WIDTH,
497				  rsz->rkisp1->info->max_width);
498	sink_fmt->height = clamp_t(u32, format->height,
499				   RKISP1_ISP_MIN_HEIGHT,
500				   rsz->rkisp1->info->max_height);
501
502	/*
503	 * Adjust the color space fields. Accept any color primaries and
504	 * transfer function for both YUV and Bayer. For YUV any YCbCr encoding
505	 * and quantization range is also accepted. For Bayer formats, the YCbCr
506	 * encoding isn't applicable, and the quantization range can only be
507	 * full.
508	 */
509	is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV;
510
511	sink_fmt->colorspace = format->colorspace ? :
512			       (is_yuv ? V4L2_COLORSPACE_SRGB :
513				V4L2_COLORSPACE_RAW);
514	sink_fmt->xfer_func = format->xfer_func ? :
515			      V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace);
516	if (is_yuv) {
517		sink_fmt->ycbcr_enc = format->ycbcr_enc ? :
518			V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace);
519		sink_fmt->quantization = format->quantization ? :
520			V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace,
521						      sink_fmt->ycbcr_enc);
522	} else {
523		/*
524		 * The YCbCr encoding isn't applicable for non-YUV formats, but
525		 * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it
526		 * should be ignored by userspace.
527		 */
528		sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
529		sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
530	}
531
532	*format = *sink_fmt;
533
534	/* Propagate the media bus code and color space to the source pad. */
535	src_fmt->code = sink_fmt->code;
536	src_fmt->colorspace = sink_fmt->colorspace;
537	src_fmt->xfer_func = sink_fmt->xfer_func;
538	src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc;
539	src_fmt->quantization = sink_fmt->quantization;
540
541	/* Update sink crop */
542	rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop);
543}
544
545static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
546			      struct v4l2_subdev_state *sd_state,
547			      struct v4l2_subdev_format *fmt)
548{
549	struct rkisp1_resizer *rsz =
550		container_of(sd, struct rkisp1_resizer, sd);
551
552	if (fmt->pad == RKISP1_RSZ_PAD_SINK)
553		rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format);
554	else
555		rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format);
556
557	return 0;
558}
559
560static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
561				    struct v4l2_subdev_state *sd_state,
562				    struct v4l2_subdev_selection *sel)
563{
564	struct v4l2_mbus_framefmt *mf_sink;
565	int ret = 0;
566
567	if (sel->pad == RKISP1_RSZ_PAD_SRC)
568		return -EINVAL;
569
570	switch (sel->target) {
571	case V4L2_SEL_TGT_CROP_BOUNDS:
572		mf_sink = v4l2_subdev_state_get_format(sd_state,
573						       RKISP1_RSZ_PAD_SINK);
574		sel->r.height = mf_sink->height;
575		sel->r.width = mf_sink->width;
576		sel->r.left = 0;
577		sel->r.top = 0;
578		break;
579
580	case V4L2_SEL_TGT_CROP:
581		sel->r = *v4l2_subdev_state_get_crop(sd_state,
582						     RKISP1_RSZ_PAD_SINK);
583		break;
584
585	default:
586		ret = -EINVAL;
587		break;
588	}
589
590	return ret;
591}
592
593static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
594				    struct v4l2_subdev_state *sd_state,
595				    struct v4l2_subdev_selection *sel)
596{
597	struct rkisp1_resizer *rsz =
598		container_of(sd, struct rkisp1_resizer, sd);
599
600	if (sel->target != V4L2_SEL_TGT_CROP || sel->pad == RKISP1_RSZ_PAD_SRC)
601		return -EINVAL;
602
603	dev_dbg(rsz->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%ux%u\n", __func__,
604		sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
605
606	rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r);
607
608	return 0;
609}
610
611static const struct media_entity_operations rkisp1_rsz_media_ops = {
612	.link_validate = v4l2_subdev_link_validate,
613};
614
615static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = {
616	.enum_mbus_code = rkisp1_rsz_enum_mbus_code,
617	.get_selection = rkisp1_rsz_get_selection,
618	.set_selection = rkisp1_rsz_set_selection,
619	.get_fmt = v4l2_subdev_get_fmt,
620	.set_fmt = rkisp1_rsz_set_fmt,
621	.link_validate = v4l2_subdev_link_validate_default,
622};
623
624/* ----------------------------------------------------------------------------
625 * Stream operations
626 */
627
628static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable)
629{
630	struct rkisp1_resizer *rsz =
631		container_of(sd, struct rkisp1_resizer, sd);
632	struct rkisp1_device *rkisp1 = rsz->rkisp1;
633	struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1];
634	enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC;
635	bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH);
636	struct v4l2_subdev_state *sd_state;
637
638	if (!enable) {
639		if (rkisp1_has_feature(rkisp1, DUAL_CROP))
640			rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC);
641		rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC);
642		return 0;
643	}
644
645	if (has_self_path && other->is_streaming)
646		when = RKISP1_SHADOW_REGS_ASYNC;
647
648	sd_state = v4l2_subdev_lock_and_get_active_state(sd);
649
650	rkisp1_rsz_config(rsz, sd_state, when);
651	if (rkisp1_has_feature(rkisp1, DUAL_CROP))
652		rkisp1_dcrop_config(rsz, sd_state);
653
654	v4l2_subdev_unlock_state(sd_state);
655
656	return 0;
657}
658
659static const struct v4l2_subdev_video_ops rkisp1_rsz_video_ops = {
660	.s_stream = rkisp1_rsz_s_stream,
661};
662
663static const struct v4l2_subdev_ops rkisp1_rsz_ops = {
664	.video = &rkisp1_rsz_video_ops,
665	.pad = &rkisp1_rsz_pad_ops,
666};
667
668static const struct v4l2_subdev_internal_ops rkisp1_rsz_internal_ops = {
669	.init_state = rkisp1_rsz_init_state,
670};
671
672static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
673{
674	if (!rsz->rkisp1)
675		return;
676
677	v4l2_device_unregister_subdev(&rsz->sd);
678	v4l2_subdev_cleanup(&rsz->sd);
679	media_entity_cleanup(&rsz->sd.entity);
680}
681
682static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
683{
684	static const char * const dev_names[] = {
685		RKISP1_RSZ_MP_DEV_NAME,
686		RKISP1_RSZ_SP_DEV_NAME
687	};
688	struct media_pad *pads = rsz->pads;
689	struct v4l2_subdev *sd = &rsz->sd;
690	int ret;
691
692	if (rsz->id == RKISP1_SELFPATH) {
693		rsz->regs_base = RKISP1_CIF_SRSZ_BASE;
694		rsz->config = &rkisp1_rsz_config_sp;
695	} else {
696		rsz->regs_base = RKISP1_CIF_MRSZ_BASE;
697		rsz->config = &rkisp1_rsz_config_mp;
698	}
699
700	v4l2_subdev_init(sd, &rkisp1_rsz_ops);
701	sd->internal_ops = &rkisp1_rsz_internal_ops;
702	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
703	sd->entity.ops = &rkisp1_rsz_media_ops;
704	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
705	sd->owner = THIS_MODULE;
706	strscpy(sd->name, dev_names[rsz->id], sizeof(sd->name));
707
708	pads[RKISP1_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
709					  MEDIA_PAD_FL_MUST_CONNECT;
710	pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE |
711					 MEDIA_PAD_FL_MUST_CONNECT;
712
713	ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads);
714	if (ret)
715		goto err_entity_cleanup;
716
717	ret = v4l2_subdev_init_finalize(sd);
718	if (ret)
719		goto err_entity_cleanup;
720
721	ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd);
722	if (ret) {
723		dev_err(sd->dev, "Failed to register resizer subdev\n");
724		goto err_subdev_cleanup;
725	}
726
727	return 0;
728
729err_subdev_cleanup:
730	v4l2_subdev_cleanup(sd);
731err_entity_cleanup:
732	media_entity_cleanup(&sd->entity);
733	return ret;
734}
735
736int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1)
737{
738	unsigned int dev_count = rkisp1_path_count(rkisp1);
739	unsigned int i;
740	int ret;
741
742	for (i = 0; i < dev_count; i++) {
743		struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i];
744
745		rsz->rkisp1 = rkisp1;
746		rsz->id = i;
747
748		ret = rkisp1_rsz_register(rsz);
749		if (ret) {
750			rsz->rkisp1 = NULL;
751			rkisp1_resizer_devs_unregister(rkisp1);
752			return ret;
753		}
754	}
755
756	return 0;
757}
758
759void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1)
760{
761	struct rkisp1_resizer *mp = &rkisp1->resizer_devs[RKISP1_MAINPATH];
762	struct rkisp1_resizer *sp = &rkisp1->resizer_devs[RKISP1_SELFPATH];
763
764	rkisp1_rsz_unregister(mp);
765	rkisp1_rsz_unregister(sp);
766}
~/ Read-only file preview.