xref: /linux/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4  *
5  * Copyright (C) STMicroelectronics SA 2023
6  * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
7  *          Alain Volmat <alain.volmat@foss.st.com>
8  *          for STMicroelectronics.
9  */
10 
11 #include <linux/vmalloc.h>
12 #include <linux/v4l2-mediabus.h>
13 #include <media/v4l2-rect.h>
14 #include <media/v4l2-subdev.h>
15 
16 #include "dcmipp-common.h"
17 
18 #define DCMIPP_P0FCTCR	0x500
19 #define DCMIPP_P0FCTCR_FRATE_MASK	GENMASK(1, 0)
20 #define DCMIPP_P0SCSTR	0x504
21 #define DCMIPP_P0SCSTR_HSTART_SHIFT	0
22 #define DCMIPP_P0SCSTR_VSTART_SHIFT	16
23 #define DCMIPP_P0SCSZR	0x508
24 #define DCMIPP_P0SCSZR_ENABLE		BIT(31)
25 #define DCMIPP_P0SCSZR_HSIZE_SHIFT	0
26 #define DCMIPP_P0SCSZR_VSIZE_SHIFT	16
27 #define DCMIPP_P0PPCR	0x5c0
28 #define DCMIPP_P0PPCR_BSM_1_2		0x1
29 #define DCMIPP_P0PPCR_BSM_1_4		0x2
30 #define DCMIPP_P0PPCR_BSM_2_4		0x3
31 #define DCMIPP_P0PPCR_BSM_MASK		GENMASK(8, 7)
32 #define DCMIPP_P0PPCR_BSM_SHIFT		0x7
33 #define DCMIPP_P0PPCR_LSM		BIT(10)
34 #define DCMIPP_P0PPCR_OELS		BIT(11)
35 
36 #define IS_SINK(pad) (!(pad))
37 #define IS_SRC(pad)  ((pad))
38 
39 struct dcmipp_byteproc_pix_map {
40 	unsigned int code;
41 	unsigned int bpp;
42 };
43 
44 #define PIXMAP_MBUS_BPP(mbus, byteperpixel)		\
45 	{						\
46 		.code = MEDIA_BUS_FMT_##mbus,		\
47 		.bpp = byteperpixel,			\
48 	}
49 static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
50 	PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
51 	PIXMAP_MBUS_BPP(RGB565_1X16, 2),
52 	PIXMAP_MBUS_BPP(RGB888_3X8, 3),
53 	PIXMAP_MBUS_BPP(RGB888_1X24, 3),
54 	PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
55 	PIXMAP_MBUS_BPP(YUYV8_1X16, 2),
56 	PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
57 	PIXMAP_MBUS_BPP(YVYU8_1X16, 2),
58 	PIXMAP_MBUS_BPP(UYVY8_2X8, 2),
59 	PIXMAP_MBUS_BPP(UYVY8_1X16, 2),
60 	PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
61 	PIXMAP_MBUS_BPP(VYUY8_1X16, 2),
62 	PIXMAP_MBUS_BPP(Y8_1X8, 1),
63 	PIXMAP_MBUS_BPP(Y10_1X10, 2),
64 	PIXMAP_MBUS_BPP(Y12_1X12, 2),
65 	PIXMAP_MBUS_BPP(Y14_1X14, 2),
66 	PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
67 	PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
68 	PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
69 	PIXMAP_MBUS_BPP(SRGGB8_1X8, 1),
70 	PIXMAP_MBUS_BPP(SBGGR10_1X10, 2),
71 	PIXMAP_MBUS_BPP(SGBRG10_1X10, 2),
72 	PIXMAP_MBUS_BPP(SGRBG10_1X10, 2),
73 	PIXMAP_MBUS_BPP(SRGGB10_1X10, 2),
74 	PIXMAP_MBUS_BPP(SBGGR12_1X12, 2),
75 	PIXMAP_MBUS_BPP(SGBRG12_1X12, 2),
76 	PIXMAP_MBUS_BPP(SGRBG12_1X12, 2),
77 	PIXMAP_MBUS_BPP(SRGGB12_1X12, 2),
78 	PIXMAP_MBUS_BPP(SBGGR14_1X14, 2),
79 	PIXMAP_MBUS_BPP(SGBRG14_1X14, 2),
80 	PIXMAP_MBUS_BPP(SGRBG14_1X14, 2),
81 	PIXMAP_MBUS_BPP(SRGGB14_1X14, 2),
82 	PIXMAP_MBUS_BPP(JPEG_1X8, 1),
83 };
84 
85 static const struct dcmipp_byteproc_pix_map *
dcmipp_byteproc_pix_map_by_code(u32 code)86 dcmipp_byteproc_pix_map_by_code(u32 code)
87 {
88 	unsigned int i;
89 
90 	for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) {
91 		if (dcmipp_byteproc_pix_map_list[i].code == code)
92 			return &dcmipp_byteproc_pix_map_list[i];
93 	}
94 
95 	return NULL;
96 }
97 
98 struct dcmipp_byteproc_device {
99 	struct dcmipp_ent_device ved;
100 	struct v4l2_subdev sd;
101 	struct device *dev;
102 	void __iomem *regs;
103 };
104 
105 static const struct v4l2_mbus_framefmt fmt_default = {
106 	.width = DCMIPP_FMT_WIDTH_DEFAULT,
107 	.height = DCMIPP_FMT_HEIGHT_DEFAULT,
108 	.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
109 	.field = V4L2_FIELD_NONE,
110 	.colorspace = DCMIPP_COLORSPACE_DEFAULT,
111 	.ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
112 	.quantization = DCMIPP_QUANTIZATION_DEFAULT,
113 	.xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
114 };
115 
116 static const struct v4l2_rect crop_min = {
117 	.width = DCMIPP_FRAME_MIN_WIDTH,
118 	.height = DCMIPP_FRAME_MIN_HEIGHT,
119 	.top = 0,
120 	.left = 0,
121 };
122 
dcmipp_byteproc_adjust_crop(struct v4l2_rect * r,struct v4l2_rect * compose)123 static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
124 					struct v4l2_rect *compose)
125 {
126 	/* Disallow rectangles smaller than the minimal one. */
127 	v4l2_rect_set_min_size(r, &crop_min);
128 	v4l2_rect_map_inside(r, compose);
129 }
130 
dcmipp_byteproc_adjust_compose(struct v4l2_rect * r,const struct v4l2_mbus_framefmt * fmt)131 static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
132 					   const struct v4l2_mbus_framefmt *fmt)
133 {
134 	const struct dcmipp_byteproc_pix_map *vpix;
135 
136 	r->top = 0;
137 	r->left = 0;
138 
139 	/* Compose is not possible for JPEG or Bayer formats */
140 	if (fmt->code >= MEDIA_BUS_FMT_SBGGR8_1X8 &&
141 	    fmt->code <= MEDIA_BUS_FMT_JPEG_1X8) {
142 		r->width = fmt->width;
143 		r->height = fmt->height;
144 		return;
145 	}
146 
147 	/* Prevent compose on formats which are not 1 or 2 bytes per pixel */
148 	vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
149 	if (vpix->bpp != 1 && vpix->bpp != 2) {
150 		r->width = fmt->width;
151 		r->height = fmt->height;
152 		return;
153 	}
154 
155 	/* Adjust height - we can only perform 1/2 decimation */
156 	if (r->height <= (fmt->height / 2))
157 		r->height = fmt->height / 2;
158 	else
159 		r->height = fmt->height;
160 
161 	/* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
162 	if (vpix->bpp == 1 && r->width <= (fmt->width / 4))
163 		r->width = fmt->width / 4;
164 	else if (r->width <= (fmt->width / 2))
165 		r->width = fmt->width / 2;
166 	else
167 		r->width = fmt->width;
168 }
169 
dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt * fmt)170 static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
171 {
172 	const struct dcmipp_byteproc_pix_map *vpix;
173 
174 	/* Only accept code in the pix map table */
175 	vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
176 	if (!vpix)
177 		fmt->code = fmt_default.code;
178 
179 	fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
180 			     DCMIPP_FRAME_MAX_WIDTH) & ~1;
181 	fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
182 			      DCMIPP_FRAME_MAX_HEIGHT) & ~1;
183 
184 	if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
185 		fmt->field = fmt_default.field;
186 
187 	dcmipp_colorimetry_clamp(fmt);
188 }
189 
dcmipp_byteproc_init_state(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)190 static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
191 				      struct v4l2_subdev_state *sd_state)
192 {
193 	unsigned int i;
194 
195 	for (i = 0; i < sd->entity.num_pads; i++) {
196 		struct v4l2_mbus_framefmt *mf;
197 		struct v4l2_rect *r;
198 
199 		mf = v4l2_subdev_state_get_format(sd_state, i);
200 		*mf = fmt_default;
201 
202 		if (IS_SINK(i))
203 			r = v4l2_subdev_state_get_compose(sd_state, i);
204 		else
205 			r = v4l2_subdev_state_get_crop(sd_state, i);
206 
207 		r->top = 0;
208 		r->left = 0;
209 		r->width = DCMIPP_FMT_WIDTH_DEFAULT;
210 		r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
211 	}
212 
213 	return 0;
214 }
215 
216 static int
dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)217 dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
218 			       struct v4l2_subdev_state *sd_state,
219 			       struct v4l2_subdev_mbus_code_enum *code)
220 {
221 	const struct dcmipp_byteproc_pix_map *vpix;
222 	struct v4l2_mbus_framefmt *sink_fmt;
223 
224 	if (IS_SINK(code->pad)) {
225 		if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
226 			return -EINVAL;
227 		vpix = &dcmipp_byteproc_pix_map_list[code->index];
228 		code->code = vpix->code;
229 	} else {
230 		/* byteproc doesn't support transformation on format */
231 		if (code->index > 0)
232 			return -EINVAL;
233 
234 		sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
235 		code->code = sink_fmt->code;
236 	}
237 
238 	return 0;
239 }
240 
241 static int
dcmipp_byteproc_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)242 dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
243 				struct v4l2_subdev_state *sd_state,
244 				struct v4l2_subdev_frame_size_enum *fse)
245 {
246 	struct v4l2_rect *compose;
247 
248 	if (fse->index)
249 		return -EINVAL;
250 
251 	fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
252 	fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
253 
254 	if (IS_SINK(fse->pad)) {
255 		fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
256 		fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
257 	} else {
258 		compose = v4l2_subdev_state_get_compose(sd_state, 0);
259 		fse->max_width = compose->width;
260 		fse->max_height = compose->height;
261 	}
262 
263 	return 0;
264 }
265 
dcmipp_byteproc_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)266 static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
267 				   struct v4l2_subdev_state *sd_state,
268 				   struct v4l2_subdev_format *fmt)
269 {
270 	struct v4l2_mbus_framefmt *mf;
271 	struct v4l2_rect *crop, *compose;
272 
273 	if (v4l2_subdev_is_streaming(sd))
274 		return -EBUSY;
275 
276 	mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
277 
278 	crop = v4l2_subdev_state_get_crop(sd_state, 1);
279 	compose = v4l2_subdev_state_get_compose(sd_state, 0);
280 
281 	if (IS_SRC(fmt->pad)) {
282 		fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
283 		fmt->format.width = crop->width;
284 		fmt->format.height = crop->height;
285 	} else {
286 		dcmipp_byteproc_adjust_fmt(&fmt->format);
287 		crop->top = 0;
288 		crop->left = 0;
289 		crop->width = fmt->format.width;
290 		crop->height = fmt->format.height;
291 		*compose = *crop;
292 		/* Set the same format on SOURCE pad as well */
293 		*v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
294 	}
295 	*mf = fmt->format;
296 
297 	return 0;
298 }
299 
dcmipp_byteproc_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * s)300 static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
301 					 struct v4l2_subdev_state *sd_state,
302 					 struct v4l2_subdev_selection *s)
303 {
304 	struct v4l2_mbus_framefmt *sink_fmt;
305 	struct v4l2_rect *crop, *compose;
306 
307 	/*
308 	 * In the HW, the decimation block is located prior to the crop hence:
309 	 * Compose is done on the sink pad
310 	 * Crop is done on the src pad
311 	 */
312 	if (IS_SINK(s->pad) &&
313 	    (s->target == V4L2_SEL_TGT_CROP ||
314 	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
315 	     s->target == V4L2_SEL_TGT_CROP_DEFAULT))
316 		return -EINVAL;
317 
318 	if (IS_SRC(s->pad) &&
319 	    (s->target == V4L2_SEL_TGT_COMPOSE ||
320 	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
321 	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
322 		return -EINVAL;
323 
324 	sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
325 	crop = v4l2_subdev_state_get_crop(sd_state, 1);
326 	compose = v4l2_subdev_state_get_compose(sd_state, 0);
327 
328 	switch (s->target) {
329 	case V4L2_SEL_TGT_CROP:
330 		s->r = *crop;
331 		break;
332 	case V4L2_SEL_TGT_CROP_BOUNDS:
333 	case V4L2_SEL_TGT_CROP_DEFAULT:
334 		s->r = *compose;
335 		break;
336 	case V4L2_SEL_TGT_COMPOSE:
337 		s->r = *compose;
338 		break;
339 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
340 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
341 		s->r.top = 0;
342 		s->r.left = 0;
343 		s->r.width = sink_fmt->width;
344 		s->r.height = sink_fmt->height;
345 		break;
346 	default:
347 		return -EINVAL;
348 	}
349 
350 	return 0;
351 }
352 
dcmipp_byteproc_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * s)353 static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
354 					 struct v4l2_subdev_state *sd_state,
355 					 struct v4l2_subdev_selection *s)
356 {
357 	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
358 	struct v4l2_mbus_framefmt *mf;
359 	struct v4l2_rect *crop, *compose;
360 
361 	/*
362 	 * In the HW, the decimation block is located prior to the crop hence:
363 	 * Compose is done on the sink pad
364 	 * Crop is done on the src pad
365 	 */
366 	if ((s->target == V4L2_SEL_TGT_CROP ||
367 	     s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
368 	     s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
369 		return -EINVAL;
370 
371 	if ((s->target == V4L2_SEL_TGT_COMPOSE ||
372 	     s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
373 	     s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
374 		return -EINVAL;
375 
376 	crop = v4l2_subdev_state_get_crop(sd_state, 1);
377 	compose = v4l2_subdev_state_get_compose(sd_state, 0);
378 
379 	switch (s->target) {
380 	case V4L2_SEL_TGT_CROP:
381 		dcmipp_byteproc_adjust_crop(&s->r, compose);
382 
383 		*crop = s->r;
384 		mf = v4l2_subdev_state_get_format(sd_state, 1);
385 		mf->width = s->r.width;
386 		mf->height = s->r.height;
387 
388 		dev_dbg(byteproc->dev, "s_selection: crop (%d,%d)/%ux%u\n",
389 			crop->left, crop->top, crop->width, crop->height);
390 		break;
391 	case V4L2_SEL_TGT_COMPOSE:
392 		mf = v4l2_subdev_state_get_format(sd_state, 0);
393 		dcmipp_byteproc_adjust_compose(&s->r, mf);
394 		*compose = s->r;
395 		*crop = s->r;
396 
397 		mf = v4l2_subdev_state_get_format(sd_state, 1);
398 		mf->width = s->r.width;
399 		mf->height = s->r.height;
400 
401 		dev_dbg(byteproc->dev, "s_selection: compose (%d,%d)/%ux%u\n",
402 			compose->left, compose->top,
403 			compose->width, compose->height);
404 		break;
405 	default:
406 		return -EINVAL;
407 	}
408 
409 	return 0;
410 }
411 
dcmipp_byteproc_configure_scale_crop(struct dcmipp_byteproc_device * byteproc,struct v4l2_subdev_state * state)412 static int dcmipp_byteproc_configure_scale_crop
413 			(struct dcmipp_byteproc_device *byteproc,
414 			 struct v4l2_subdev_state *state)
415 {
416 	const struct dcmipp_byteproc_pix_map *vpix;
417 	struct v4l2_mbus_framefmt *sink_fmt;
418 	u32 hprediv, vprediv;
419 	struct v4l2_rect *compose, *crop;
420 	u32 val = 0;
421 
422 	sink_fmt = v4l2_subdev_state_get_format(state, 0);
423 	compose = v4l2_subdev_state_get_compose(state, 0);
424 	crop = v4l2_subdev_state_get_crop(state, 1);
425 
426 	/* find output format bpp */
427 	vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
428 	if (!vpix)
429 		return -EINVAL;
430 
431 	/* clear decimation/crop */
432 	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
433 	reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
434 	reg_write(byteproc, DCMIPP_P0SCSTR, 0);
435 	reg_write(byteproc, DCMIPP_P0SCSZR, 0);
436 
437 	/* Ignore decimation/crop with JPEG */
438 	if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
439 		return 0;
440 
441 	/* decimation */
442 	hprediv = sink_fmt->width / compose->width;
443 	if (hprediv == 4)
444 		val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
445 	else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
446 		val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
447 	else if (hprediv == 2)
448 		val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
449 
450 	vprediv = sink_fmt->height / compose->height;
451 	if (vprediv == 2)
452 		val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
453 
454 	/* decimate using bytes and lines skipping */
455 	if (val) {
456 		reg_set(byteproc, DCMIPP_P0PPCR, val);
457 
458 		dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
459 			compose->width, compose->height,
460 			hprediv, vprediv);
461 	}
462 
463 	dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
464 
465 	/* expressed in 32-bits words on X axis, lines on Y axis */
466 	reg_write(byteproc, DCMIPP_P0SCSTR,
467 		  (((crop->left * vpix->bpp) / 4) <<
468 		   DCMIPP_P0SCSTR_HSTART_SHIFT) |
469 		  (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
470 	reg_write(byteproc, DCMIPP_P0SCSZR,
471 		  DCMIPP_P0SCSZR_ENABLE |
472 		  (((crop->width * vpix->bpp) / 4) <<
473 		   DCMIPP_P0SCSZR_HSIZE_SHIFT) |
474 		  (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
475 
476 	return 0;
477 }
478 
dcmipp_byteproc_enable_streams(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,u32 pad,u64 streams_mask)479 static int dcmipp_byteproc_enable_streams(struct v4l2_subdev *sd,
480 					  struct v4l2_subdev_state *state,
481 					  u32 pad, u64 streams_mask)
482 {
483 	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
484 	struct v4l2_subdev *s_subdev;
485 	struct media_pad *s_pad;
486 	int ret;
487 
488 	/* Get source subdev */
489 	s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
490 	if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
491 		return -EINVAL;
492 	s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
493 
494 	ret = dcmipp_byteproc_configure_scale_crop(byteproc, state);
495 	if (ret)
496 		return ret;
497 
498 	ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
499 	if (ret < 0) {
500 		dev_err(byteproc->dev,
501 			"failed to start source subdev streaming (%d)\n", ret);
502 		return ret;
503 	}
504 
505 	return 0;
506 }
507 
dcmipp_byteproc_disable_streams(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,u32 pad,u64 streams_mask)508 static int dcmipp_byteproc_disable_streams(struct v4l2_subdev *sd,
509 					   struct v4l2_subdev_state *state,
510 					   u32 pad, u64 streams_mask)
511 {
512 	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
513 	struct v4l2_subdev *s_subdev;
514 	struct media_pad *s_pad;
515 	int ret;
516 
517 	/* Get source subdev */
518 	s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
519 	if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
520 		return -EINVAL;
521 	s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
522 
523 	ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
524 	if (ret < 0) {
525 		dev_err(byteproc->dev,
526 			"failed to start source subdev streaming (%d)\n", ret);
527 		return ret;
528 	}
529 
530 	return 0;
531 }
532 
533 static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
534 	.enum_mbus_code		= dcmipp_byteproc_enum_mbus_code,
535 	.enum_frame_size	= dcmipp_byteproc_enum_frame_size,
536 	.get_fmt		= v4l2_subdev_get_fmt,
537 	.set_fmt		= dcmipp_byteproc_set_fmt,
538 	.get_selection		= dcmipp_byteproc_get_selection,
539 	.set_selection		= dcmipp_byteproc_set_selection,
540 	.enable_streams		= dcmipp_byteproc_enable_streams,
541 	.disable_streams	= dcmipp_byteproc_disable_streams,
542 };
543 
544 static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
545 	.s_stream = v4l2_subdev_s_stream_helper,
546 };
547 
548 static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
549 	.pad = &dcmipp_byteproc_pad_ops,
550 	.video = &dcmipp_byteproc_video_ops,
551 };
552 
dcmipp_byteproc_release(struct v4l2_subdev * sd)553 static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
554 {
555 	struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
556 
557 	kfree(byteproc);
558 }
559 
560 static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
561 	.init_state = dcmipp_byteproc_init_state,
562 	.release = dcmipp_byteproc_release,
563 };
564 
dcmipp_byteproc_ent_release(struct dcmipp_ent_device * ved)565 void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
566 {
567 	struct dcmipp_byteproc_device *byteproc =
568 			container_of(ved, struct dcmipp_byteproc_device, ved);
569 
570 	dcmipp_ent_sd_unregister(ved, &byteproc->sd);
571 }
572 
573 struct dcmipp_ent_device *
dcmipp_byteproc_ent_init(struct device * dev,const char * entity_name,struct v4l2_device * v4l2_dev,void __iomem * regs)574 dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
575 			 struct v4l2_device *v4l2_dev, void __iomem *regs)
576 {
577 	struct dcmipp_byteproc_device *byteproc;
578 	const unsigned long pads_flag[] = {
579 		MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
580 	};
581 	int ret;
582 
583 	/* Allocate the byteproc struct */
584 	byteproc = kzalloc_obj(*byteproc);
585 	if (!byteproc)
586 		return ERR_PTR(-ENOMEM);
587 
588 	byteproc->regs = regs;
589 
590 	/* Initialize ved and sd */
591 	ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
592 				     v4l2_dev, entity_name,
593 				     MEDIA_ENT_F_PROC_VIDEO_SCALER,
594 				     ARRAY_SIZE(pads_flag), pads_flag,
595 				     &dcmipp_byteproc_int_ops,
596 				     &dcmipp_byteproc_ops,
597 				     NULL, NULL);
598 	if (ret) {
599 		kfree(byteproc);
600 		return ERR_PTR(ret);
601 	}
602 
603 	byteproc->dev = dev;
604 
605 	return &byteproc->ved;
606 }
607