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