1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * V4L2 Capture IC Preprocess Subdev for Freescale i.MX5/6 SOC
4  *
5  * This subdevice handles capture of video frames from the CSI or VDIC,
6  * which are routed directly to the Image Converter preprocess tasks,
7  * for resizing, colorspace conversion, and rotation.
8  *
9  * Copyright (c) 2012-2017 Mentor Graphics Inc.
10  */
11 #include <linux/delay.h>
12 #include <linux/interrupt.h>
13 #include <linux/module.h>
14 #include <linux/sched.h>
15 #include <linux/slab.h>
16 #include <linux/spinlock.h>
17 #include <linux/timer.h>
18 #include <media/v4l2-ctrls.h>
19 #include <media/v4l2-device.h>
20 #include <media/v4l2-ioctl.h>
21 #include <media/v4l2-subdev.h>
22 #include <media/imx.h>
23 #include "imx-media.h"
24 #include "imx-ic.h"
25 
26 /*
27  * Min/Max supported width and heights.
28  */
29 #define MIN_W        32
30 #define MIN_H        32
31 #define MAX_W      4096
32 #define MAX_H      4096
33 #define W_ALIGN    4 /* multiple of 16 pixels */
34 #define H_ALIGN    1 /* multiple of 2 lines */
35 #define S_ALIGN    1 /* multiple of 2 */
36 
37 struct prp_priv {
38 	struct imx_ic_priv *ic_priv;
39 	struct media_pad pad[PRP_NUM_PADS];
40 
41 	/* lock to protect all members below */
42 	struct mutex lock;
43 
44 	struct v4l2_subdev *src_sd;
45 	struct v4l2_subdev *sink_sd_prpenc;
46 	struct v4l2_subdev *sink_sd_prpvf;
47 
48 	/* the CSI id at link validate */
49 	int csi_id;
50 
51 	struct v4l2_mbus_framefmt format_mbus;
52 	struct v4l2_fract frame_interval;
53 
54 	int stream_count;
55 };
56 
sd_to_priv(struct v4l2_subdev * sd)57 static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
58 {
59 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
60 
61 	return ic_priv->task_priv;
62 }
63 
prp_start(struct prp_priv * priv)64 static int prp_start(struct prp_priv *priv)
65 {
66 	struct imx_ic_priv *ic_priv = priv->ic_priv;
67 	bool src_is_vdic;
68 
69 	/* set IC to receive from CSI or VDI depending on source */
70 	src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
71 
72 	ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic);
73 
74 	return 0;
75 }
76 
prp_stop(struct prp_priv * priv)77 static void prp_stop(struct prp_priv *priv)
78 {
79 }
80 
81 static struct v4l2_mbus_framefmt *
__prp_get_fmt(struct prp_priv * priv,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)82 __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
83 	      unsigned int pad, enum v4l2_subdev_format_whence which)
84 {
85 	struct imx_ic_priv *ic_priv = priv->ic_priv;
86 
87 	if (which == V4L2_SUBDEV_FORMAT_TRY)
88 		return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
89 	else
90 		return &priv->format_mbus;
91 }
92 
93 /*
94  * V4L2 subdev operations.
95  */
96 
prp_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)97 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
98 			      struct v4l2_subdev_state *sd_state,
99 			      struct v4l2_subdev_mbus_code_enum *code)
100 {
101 	struct prp_priv *priv = sd_to_priv(sd);
102 	struct v4l2_mbus_framefmt *infmt;
103 	int ret = 0;
104 
105 	mutex_lock(&priv->lock);
106 
107 	switch (code->pad) {
108 	case PRP_SINK_PAD:
109 		ret = imx_media_enum_ipu_formats(&code->code, code->index,
110 						 PIXFMT_SEL_YUV_RGB);
111 		break;
112 	case PRP_SRC_PAD_PRPENC:
113 	case PRP_SRC_PAD_PRPVF:
114 		if (code->index != 0) {
115 			ret = -EINVAL;
116 			goto out;
117 		}
118 		infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD,
119 				      code->which);
120 		code->code = infmt->code;
121 		break;
122 	default:
123 		ret = -EINVAL;
124 	}
125 out:
126 	mutex_unlock(&priv->lock);
127 	return ret;
128 }
129 
prp_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * sdformat)130 static int prp_get_fmt(struct v4l2_subdev *sd,
131 		       struct v4l2_subdev_state *sd_state,
132 		       struct v4l2_subdev_format *sdformat)
133 {
134 	struct prp_priv *priv = sd_to_priv(sd);
135 	struct v4l2_mbus_framefmt *fmt;
136 	int ret = 0;
137 
138 	if (sdformat->pad >= PRP_NUM_PADS)
139 		return -EINVAL;
140 
141 	mutex_lock(&priv->lock);
142 
143 	fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
144 	if (!fmt) {
145 		ret = -EINVAL;
146 		goto out;
147 	}
148 
149 	sdformat->format = *fmt;
150 out:
151 	mutex_unlock(&priv->lock);
152 	return ret;
153 }
154 
prp_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * sdformat)155 static int prp_set_fmt(struct v4l2_subdev *sd,
156 		       struct v4l2_subdev_state *sd_state,
157 		       struct v4l2_subdev_format *sdformat)
158 {
159 	struct prp_priv *priv = sd_to_priv(sd);
160 	struct v4l2_mbus_framefmt *fmt, *infmt;
161 	const struct imx_media_pixfmt *cc;
162 	int ret = 0;
163 	u32 code;
164 
165 	if (sdformat->pad >= PRP_NUM_PADS)
166 		return -EINVAL;
167 
168 	mutex_lock(&priv->lock);
169 
170 	if (priv->stream_count > 0) {
171 		ret = -EBUSY;
172 		goto out;
173 	}
174 
175 	infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, sdformat->which);
176 
177 	switch (sdformat->pad) {
178 	case PRP_SINK_PAD:
179 		v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
180 				      W_ALIGN, &sdformat->format.height,
181 				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
182 
183 		cc = imx_media_find_ipu_format(sdformat->format.code,
184 					       PIXFMT_SEL_YUV_RGB);
185 		if (!cc) {
186 			imx_media_enum_ipu_formats(&code, 0,
187 						   PIXFMT_SEL_YUV_RGB);
188 			cc = imx_media_find_ipu_format(code,
189 						       PIXFMT_SEL_YUV_RGB);
190 			sdformat->format.code = cc->codes[0];
191 		}
192 
193 		if (sdformat->format.field == V4L2_FIELD_ANY)
194 			sdformat->format.field = V4L2_FIELD_NONE;
195 		break;
196 	case PRP_SRC_PAD_PRPENC:
197 	case PRP_SRC_PAD_PRPVF:
198 		/* Output pads mirror input pad */
199 		sdformat->format = *infmt;
200 		break;
201 	}
202 
203 	imx_media_try_colorimetry(&sdformat->format, true);
204 
205 	fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
206 	*fmt = sdformat->format;
207 out:
208 	mutex_unlock(&priv->lock);
209 	return ret;
210 }
211 
prp_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)212 static int prp_link_setup(struct media_entity *entity,
213 			  const struct media_pad *local,
214 			  const struct media_pad *remote, u32 flags)
215 {
216 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
217 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
218 	struct prp_priv *priv = ic_priv->task_priv;
219 	struct v4l2_subdev *remote_sd;
220 	int ret = 0;
221 
222 	dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
223 		ic_priv->sd.name, remote->entity->name, local->entity->name);
224 
225 	remote_sd = media_entity_to_v4l2_subdev(remote->entity);
226 
227 	mutex_lock(&priv->lock);
228 
229 	if (local->flags & MEDIA_PAD_FL_SINK) {
230 		if (flags & MEDIA_LNK_FL_ENABLED) {
231 			if (priv->src_sd) {
232 				ret = -EBUSY;
233 				goto out;
234 			}
235 			if (priv->sink_sd_prpenc &&
236 			    (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) {
237 				ret = -EINVAL;
238 				goto out;
239 			}
240 			priv->src_sd = remote_sd;
241 		} else {
242 			priv->src_sd = NULL;
243 		}
244 
245 		goto out;
246 	}
247 
248 	/* this is a source pad */
249 	if (flags & MEDIA_LNK_FL_ENABLED) {
250 		switch (local->index) {
251 		case PRP_SRC_PAD_PRPENC:
252 			if (priv->sink_sd_prpenc) {
253 				ret = -EBUSY;
254 				goto out;
255 			}
256 			if (priv->src_sd && (priv->src_sd->grp_id &
257 					     IMX_MEDIA_GRP_ID_IPU_VDIC)) {
258 				ret = -EINVAL;
259 				goto out;
260 			}
261 			priv->sink_sd_prpenc = remote_sd;
262 			break;
263 		case PRP_SRC_PAD_PRPVF:
264 			if (priv->sink_sd_prpvf) {
265 				ret = -EBUSY;
266 				goto out;
267 			}
268 			priv->sink_sd_prpvf = remote_sd;
269 			break;
270 		default:
271 			ret = -EINVAL;
272 		}
273 	} else {
274 		switch (local->index) {
275 		case PRP_SRC_PAD_PRPENC:
276 			priv->sink_sd_prpenc = NULL;
277 			break;
278 		case PRP_SRC_PAD_PRPVF:
279 			priv->sink_sd_prpvf = NULL;
280 			break;
281 		default:
282 			ret = -EINVAL;
283 		}
284 	}
285 
286 out:
287 	mutex_unlock(&priv->lock);
288 	return ret;
289 }
290 
prp_link_validate(struct v4l2_subdev * sd,struct media_link * link,struct v4l2_subdev_format * source_fmt,struct v4l2_subdev_format * sink_fmt)291 static int prp_link_validate(struct v4l2_subdev *sd,
292 			     struct media_link *link,
293 			     struct v4l2_subdev_format *source_fmt,
294 			     struct v4l2_subdev_format *sink_fmt)
295 {
296 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
297 	struct prp_priv *priv = ic_priv->task_priv;
298 	struct v4l2_subdev *csi;
299 	int ret;
300 
301 	ret = v4l2_subdev_link_validate_default(sd, link,
302 						source_fmt, sink_fmt);
303 	if (ret)
304 		return ret;
305 
306 	csi = imx_media_pipeline_subdev(&ic_priv->sd.entity,
307 					IMX_MEDIA_GRP_ID_IPU_CSI, true);
308 	if (IS_ERR(csi))
309 		csi = NULL;
310 
311 	mutex_lock(&priv->lock);
312 
313 	if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
314 		/*
315 		 * the ->PRPENC link cannot be enabled if the source
316 		 * is the VDIC
317 		 */
318 		if (priv->sink_sd_prpenc) {
319 			ret = -EINVAL;
320 			goto out;
321 		}
322 	} else {
323 		/* the source is a CSI */
324 		if (!csi) {
325 			ret = -EINVAL;
326 			goto out;
327 		}
328 	}
329 
330 	if (csi) {
331 		switch (csi->grp_id) {
332 		case IMX_MEDIA_GRP_ID_IPU_CSI0:
333 			priv->csi_id = 0;
334 			break;
335 		case IMX_MEDIA_GRP_ID_IPU_CSI1:
336 			priv->csi_id = 1;
337 			break;
338 		default:
339 			ret = -EINVAL;
340 		}
341 	} else {
342 		priv->csi_id = 0;
343 	}
344 
345 out:
346 	mutex_unlock(&priv->lock);
347 	return ret;
348 }
349 
prp_s_stream(struct v4l2_subdev * sd,int enable)350 static int prp_s_stream(struct v4l2_subdev *sd, int enable)
351 {
352 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
353 	struct prp_priv *priv = ic_priv->task_priv;
354 	int ret = 0;
355 
356 	mutex_lock(&priv->lock);
357 
358 	if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) {
359 		ret = -EPIPE;
360 		goto out;
361 	}
362 
363 	/*
364 	 * enable/disable streaming only if stream_count is
365 	 * going from 0 to 1 / 1 to 0.
366 	 */
367 	if (priv->stream_count != !enable)
368 		goto update_count;
369 
370 	dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
371 		enable ? "ON" : "OFF");
372 
373 	if (enable)
374 		ret = prp_start(priv);
375 	else
376 		prp_stop(priv);
377 	if (ret)
378 		goto out;
379 
380 	/* start/stop upstream */
381 	ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
382 	ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
383 	if (ret) {
384 		if (enable)
385 			prp_stop(priv);
386 		goto out;
387 	}
388 
389 update_count:
390 	priv->stream_count += enable ? 1 : -1;
391 	if (priv->stream_count < 0)
392 		priv->stream_count = 0;
393 out:
394 	mutex_unlock(&priv->lock);
395 	return ret;
396 }
397 
prp_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)398 static int prp_g_frame_interval(struct v4l2_subdev *sd,
399 				struct v4l2_subdev_frame_interval *fi)
400 {
401 	struct prp_priv *priv = sd_to_priv(sd);
402 
403 	if (fi->pad >= PRP_NUM_PADS)
404 		return -EINVAL;
405 
406 	mutex_lock(&priv->lock);
407 	fi->interval = priv->frame_interval;
408 	mutex_unlock(&priv->lock);
409 
410 	return 0;
411 }
412 
prp_s_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)413 static int prp_s_frame_interval(struct v4l2_subdev *sd,
414 				struct v4l2_subdev_frame_interval *fi)
415 {
416 	struct prp_priv *priv = sd_to_priv(sd);
417 
418 	if (fi->pad >= PRP_NUM_PADS)
419 		return -EINVAL;
420 
421 	mutex_lock(&priv->lock);
422 
423 	/* No limits on valid frame intervals */
424 	if (fi->interval.numerator == 0 || fi->interval.denominator == 0)
425 		fi->interval = priv->frame_interval;
426 	else
427 		priv->frame_interval = fi->interval;
428 
429 	mutex_unlock(&priv->lock);
430 
431 	return 0;
432 }
433 
prp_registered(struct v4l2_subdev * sd)434 static int prp_registered(struct v4l2_subdev *sd)
435 {
436 	struct prp_priv *priv = sd_to_priv(sd);
437 	u32 code;
438 
439 	/* init default frame interval */
440 	priv->frame_interval.numerator = 1;
441 	priv->frame_interval.denominator = 30;
442 
443 	/* set a default mbus format  */
444 	imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
445 
446 	return imx_media_init_mbus_fmt(&priv->format_mbus,
447 				       IMX_MEDIA_DEF_PIX_WIDTH,
448 				       IMX_MEDIA_DEF_PIX_HEIGHT, code,
449 				       V4L2_FIELD_NONE, NULL);
450 }
451 
452 static const struct v4l2_subdev_pad_ops prp_pad_ops = {
453 	.init_cfg = imx_media_init_cfg,
454 	.enum_mbus_code = prp_enum_mbus_code,
455 	.get_fmt = prp_get_fmt,
456 	.set_fmt = prp_set_fmt,
457 	.link_validate = prp_link_validate,
458 };
459 
460 static const struct v4l2_subdev_video_ops prp_video_ops = {
461 	.g_frame_interval = prp_g_frame_interval,
462 	.s_frame_interval = prp_s_frame_interval,
463 	.s_stream = prp_s_stream,
464 };
465 
466 static const struct media_entity_operations prp_entity_ops = {
467 	.link_setup = prp_link_setup,
468 	.link_validate = v4l2_subdev_link_validate,
469 };
470 
471 static const struct v4l2_subdev_ops prp_subdev_ops = {
472 	.video = &prp_video_ops,
473 	.pad = &prp_pad_ops,
474 };
475 
476 static const struct v4l2_subdev_internal_ops prp_internal_ops = {
477 	.registered = prp_registered,
478 };
479 
prp_init(struct imx_ic_priv * ic_priv)480 static int prp_init(struct imx_ic_priv *ic_priv)
481 {
482 	struct prp_priv *priv;
483 	int i;
484 
485 	priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
486 	if (!priv)
487 		return -ENOMEM;
488 
489 	mutex_init(&priv->lock);
490 	ic_priv->task_priv = priv;
491 	priv->ic_priv = ic_priv;
492 
493 	for (i = 0; i < PRP_NUM_PADS; i++)
494 		priv->pad[i].flags = (i == PRP_SINK_PAD) ?
495 			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
496 
497 	return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS,
498 				      priv->pad);
499 }
500 
prp_remove(struct imx_ic_priv * ic_priv)501 static void prp_remove(struct imx_ic_priv *ic_priv)
502 {
503 	struct prp_priv *priv = ic_priv->task_priv;
504 
505 	mutex_destroy(&priv->lock);
506 }
507 
508 struct imx_ic_ops imx_ic_prp_ops = {
509 	.subdev_ops = &prp_subdev_ops,
510 	.internal_ops = &prp_internal_ops,
511 	.entity_ops = &prp_entity_ops,
512 	.init = prp_init,
513 	.remove = prp_remove,
514 };
515