brintos

brintos / linux-shallow public Read only

0
0
Text · 22.0 KiB · f073e72 Raw
767 lines · c
1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)2/*3 * Rockchip ISP1 Driver - V4l resizer device4 *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_2X817#define RKISP1_DEF_PIXEL_ENC V4L2_PIXEL_ENC_YUV18 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 configs119 */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	else132		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 configs172 */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	else182		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 bayer284	 * 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 frame302	 * but also to change the subsampling for YUV formats (for instance303	 * converting from 4:2:2 to 4:2:0). Check both the luma and chroma304	 * 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 operations325 */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 resizer345	 * should support only YUV422 on the sink pad346	 */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 ISP356	 * 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	else487		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 and504	 * transfer function for both YUV and Bayer. For YUV any YCbCr encoding505	 * and quantization range is also accepted. For Bayer formats, the YCbCr506	 * encoding isn't applicable, and the quantization range can only be507	 * 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, but525		 * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it526		 * 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	else555		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)/%dx%d\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 operations626 */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_NAME687	};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}767