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_pad_config * cfg,unsigned int pad,enum v4l2_subdev_format_whence which)82 __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
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, cfg, 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_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)97 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
98 			      struct v4l2_subdev_pad_config *cfg,
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, cfg, PRP_SINK_PAD, code->which);
119 		code->code = infmt->code;
120 		break;
121 	default:
122 		ret = -EINVAL;
123 	}
124 out:
125 	mutex_unlock(&priv->lock);
126 	return ret;
127 }
128 
prp_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * sdformat)129 static int prp_get_fmt(struct v4l2_subdev *sd,
130 		       struct v4l2_subdev_pad_config *cfg,
131 		       struct v4l2_subdev_format *sdformat)
132 {
133 	struct prp_priv *priv = sd_to_priv(sd);
134 	struct v4l2_mbus_framefmt *fmt;
135 	int ret = 0;
136 
137 	if (sdformat->pad >= PRP_NUM_PADS)
138 		return -EINVAL;
139 
140 	mutex_lock(&priv->lock);
141 
142 	fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
143 	if (!fmt) {
144 		ret = -EINVAL;
145 		goto out;
146 	}
147 
148 	sdformat->format = *fmt;
149 out:
150 	mutex_unlock(&priv->lock);
151 	return ret;
152 }
153 
prp_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * sdformat)154 static int prp_set_fmt(struct v4l2_subdev *sd,
155 		       struct v4l2_subdev_pad_config *cfg,
156 		       struct v4l2_subdev_format *sdformat)
157 {
158 	struct prp_priv *priv = sd_to_priv(sd);
159 	struct v4l2_mbus_framefmt *fmt, *infmt;
160 	const struct imx_media_pixfmt *cc;
161 	int ret = 0;
162 	u32 code;
163 
164 	if (sdformat->pad >= PRP_NUM_PADS)
165 		return -EINVAL;
166 
167 	mutex_lock(&priv->lock);
168 
169 	if (priv->stream_count > 0) {
170 		ret = -EBUSY;
171 		goto out;
172 	}
173 
174 	infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which);
175 
176 	switch (sdformat->pad) {
177 	case PRP_SINK_PAD:
178 		v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
179 				      W_ALIGN, &sdformat->format.height,
180 				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
181 
182 		cc = imx_media_find_ipu_format(sdformat->format.code,
183 					       PIXFMT_SEL_YUV_RGB);
184 		if (!cc) {
185 			imx_media_enum_ipu_formats(&code, 0,
186 						   PIXFMT_SEL_YUV_RGB);
187 			cc = imx_media_find_ipu_format(code,
188 						       PIXFMT_SEL_YUV_RGB);
189 			sdformat->format.code = cc->codes[0];
190 		}
191 
192 		if (sdformat->format.field == V4L2_FIELD_ANY)
193 			sdformat->format.field = V4L2_FIELD_NONE;
194 		break;
195 	case PRP_SRC_PAD_PRPENC:
196 	case PRP_SRC_PAD_PRPVF:
197 		/* Output pads mirror input pad */
198 		sdformat->format = *infmt;
199 		break;
200 	}
201 
202 	imx_media_try_colorimetry(&sdformat->format, true);
203 
204 	fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
205 	*fmt = sdformat->format;
206 out:
207 	mutex_unlock(&priv->lock);
208 	return ret;
209 }
210 
prp_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)211 static int prp_link_setup(struct media_entity *entity,
212 			  const struct media_pad *local,
213 			  const struct media_pad *remote, u32 flags)
214 {
215 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
216 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
217 	struct prp_priv *priv = ic_priv->task_priv;
218 	struct v4l2_subdev *remote_sd;
219 	int ret = 0;
220 
221 	dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
222 		ic_priv->sd.name, remote->entity->name, local->entity->name);
223 
224 	remote_sd = media_entity_to_v4l2_subdev(remote->entity);
225 
226 	mutex_lock(&priv->lock);
227 
228 	if (local->flags & MEDIA_PAD_FL_SINK) {
229 		if (flags & MEDIA_LNK_FL_ENABLED) {
230 			if (priv->src_sd) {
231 				ret = -EBUSY;
232 				goto out;
233 			}
234 			if (priv->sink_sd_prpenc &&
235 			    (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) {
236 				ret = -EINVAL;
237 				goto out;
238 			}
239 			priv->src_sd = remote_sd;
240 		} else {
241 			priv->src_sd = NULL;
242 		}
243 
244 		goto out;
245 	}
246 
247 	/* this is a source pad */
248 	if (flags & MEDIA_LNK_FL_ENABLED) {
249 		switch (local->index) {
250 		case PRP_SRC_PAD_PRPENC:
251 			if (priv->sink_sd_prpenc) {
252 				ret = -EBUSY;
253 				goto out;
254 			}
255 			if (priv->src_sd && (priv->src_sd->grp_id &
256 					     IMX_MEDIA_GRP_ID_IPU_VDIC)) {
257 				ret = -EINVAL;
258 				goto out;
259 			}
260 			priv->sink_sd_prpenc = remote_sd;
261 			break;
262 		case PRP_SRC_PAD_PRPVF:
263 			if (priv->sink_sd_prpvf) {
264 				ret = -EBUSY;
265 				goto out;
266 			}
267 			priv->sink_sd_prpvf = remote_sd;
268 			break;
269 		default:
270 			ret = -EINVAL;
271 		}
272 	} else {
273 		switch (local->index) {
274 		case PRP_SRC_PAD_PRPENC:
275 			priv->sink_sd_prpenc = NULL;
276 			break;
277 		case PRP_SRC_PAD_PRPVF:
278 			priv->sink_sd_prpvf = NULL;
279 			break;
280 		default:
281 			ret = -EINVAL;
282 		}
283 	}
284 
285 out:
286 	mutex_unlock(&priv->lock);
287 	return ret;
288 }
289 
prp_link_validate(struct v4l2_subdev * sd,struct media_link * link,struct v4l2_subdev_format * source_fmt,struct v4l2_subdev_format * sink_fmt)290 static int prp_link_validate(struct v4l2_subdev *sd,
291 			     struct media_link *link,
292 			     struct v4l2_subdev_format *source_fmt,
293 			     struct v4l2_subdev_format *sink_fmt)
294 {
295 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
296 	struct prp_priv *priv = ic_priv->task_priv;
297 	struct v4l2_subdev *csi;
298 	int ret;
299 
300 	ret = v4l2_subdev_link_validate_default(sd, link,
301 						source_fmt, sink_fmt);
302 	if (ret)
303 		return ret;
304 
305 	csi = imx_media_pipeline_subdev(&ic_priv->sd.entity,
306 					IMX_MEDIA_GRP_ID_IPU_CSI, true);
307 	if (IS_ERR(csi))
308 		csi = NULL;
309 
310 	mutex_lock(&priv->lock);
311 
312 	if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
313 		/*
314 		 * the ->PRPENC link cannot be enabled if the source
315 		 * is the VDIC
316 		 */
317 		if (priv->sink_sd_prpenc) {
318 			ret = -EINVAL;
319 			goto out;
320 		}
321 	} else {
322 		/* the source is a CSI */
323 		if (!csi) {
324 			ret = -EINVAL;
325 			goto out;
326 		}
327 	}
328 
329 	if (csi) {
330 		switch (csi->grp_id) {
331 		case IMX_MEDIA_GRP_ID_IPU_CSI0:
332 			priv->csi_id = 0;
333 			break;
334 		case IMX_MEDIA_GRP_ID_IPU_CSI1:
335 			priv->csi_id = 1;
336 			break;
337 		default:
338 			ret = -EINVAL;
339 		}
340 	} else {
341 		priv->csi_id = 0;
342 	}
343 
344 out:
345 	mutex_unlock(&priv->lock);
346 	return ret;
347 }
348 
prp_s_stream(struct v4l2_subdev * sd,int enable)349 static int prp_s_stream(struct v4l2_subdev *sd, int enable)
350 {
351 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
352 	struct prp_priv *priv = ic_priv->task_priv;
353 	int ret = 0;
354 
355 	mutex_lock(&priv->lock);
356 
357 	if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) {
358 		ret = -EPIPE;
359 		goto out;
360 	}
361 
362 	/*
363 	 * enable/disable streaming only if stream_count is
364 	 * going from 0 to 1 / 1 to 0.
365 	 */
366 	if (priv->stream_count != !enable)
367 		goto update_count;
368 
369 	dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
370 		enable ? "ON" : "OFF");
371 
372 	if (enable)
373 		ret = prp_start(priv);
374 	else
375 		prp_stop(priv);
376 	if (ret)
377 		goto out;
378 
379 	/* start/stop upstream */
380 	ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
381 	ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
382 	if (ret) {
383 		if (enable)
384 			prp_stop(priv);
385 		goto out;
386 	}
387 
388 update_count:
389 	priv->stream_count += enable ? 1 : -1;
390 	if (priv->stream_count < 0)
391 		priv->stream_count = 0;
392 out:
393 	mutex_unlock(&priv->lock);
394 	return ret;
395 }
396 
prp_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)397 static int prp_g_frame_interval(struct v4l2_subdev *sd,
398 				struct v4l2_subdev_frame_interval *fi)
399 {
400 	struct prp_priv *priv = sd_to_priv(sd);
401 
402 	if (fi->pad >= PRP_NUM_PADS)
403 		return -EINVAL;
404 
405 	mutex_lock(&priv->lock);
406 	fi->interval = priv->frame_interval;
407 	mutex_unlock(&priv->lock);
408 
409 	return 0;
410 }
411 
prp_s_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)412 static int prp_s_frame_interval(struct v4l2_subdev *sd,
413 				struct v4l2_subdev_frame_interval *fi)
414 {
415 	struct prp_priv *priv = sd_to_priv(sd);
416 
417 	if (fi->pad >= PRP_NUM_PADS)
418 		return -EINVAL;
419 
420 	mutex_lock(&priv->lock);
421 
422 	/* No limits on valid frame intervals */
423 	if (fi->interval.numerator == 0 || fi->interval.denominator == 0)
424 		fi->interval = priv->frame_interval;
425 	else
426 		priv->frame_interval = fi->interval;
427 
428 	mutex_unlock(&priv->lock);
429 
430 	return 0;
431 }
432 
prp_registered(struct v4l2_subdev * sd)433 static int prp_registered(struct v4l2_subdev *sd)
434 {
435 	struct prp_priv *priv = sd_to_priv(sd);
436 	u32 code;
437 
438 	/* init default frame interval */
439 	priv->frame_interval.numerator = 1;
440 	priv->frame_interval.denominator = 30;
441 
442 	/* set a default mbus format  */
443 	imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
444 
445 	return imx_media_init_mbus_fmt(&priv->format_mbus,
446 				       IMX_MEDIA_DEF_PIX_WIDTH,
447 				       IMX_MEDIA_DEF_PIX_HEIGHT, code,
448 				       V4L2_FIELD_NONE, NULL);
449 }
450 
451 static const struct v4l2_subdev_pad_ops prp_pad_ops = {
452 	.init_cfg = imx_media_init_cfg,
453 	.enum_mbus_code = prp_enum_mbus_code,
454 	.get_fmt = prp_get_fmt,
455 	.set_fmt = prp_set_fmt,
456 	.link_validate = prp_link_validate,
457 };
458 
459 static const struct v4l2_subdev_video_ops prp_video_ops = {
460 	.g_frame_interval = prp_g_frame_interval,
461 	.s_frame_interval = prp_s_frame_interval,
462 	.s_stream = prp_s_stream,
463 };
464 
465 static const struct media_entity_operations prp_entity_ops = {
466 	.link_setup = prp_link_setup,
467 	.link_validate = v4l2_subdev_link_validate,
468 };
469 
470 static const struct v4l2_subdev_ops prp_subdev_ops = {
471 	.video = &prp_video_ops,
472 	.pad = &prp_pad_ops,
473 };
474 
475 static const struct v4l2_subdev_internal_ops prp_internal_ops = {
476 	.registered = prp_registered,
477 };
478 
prp_init(struct imx_ic_priv * ic_priv)479 static int prp_init(struct imx_ic_priv *ic_priv)
480 {
481 	struct prp_priv *priv;
482 	int i;
483 
484 	priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
485 	if (!priv)
486 		return -ENOMEM;
487 
488 	mutex_init(&priv->lock);
489 	ic_priv->task_priv = priv;
490 	priv->ic_priv = ic_priv;
491 
492 	for (i = 0; i < PRP_NUM_PADS; i++)
493 		priv->pad[i].flags = (i == PRP_SINK_PAD) ?
494 			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
495 
496 	return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS,
497 				      priv->pad);
498 }
499 
prp_remove(struct imx_ic_priv * ic_priv)500 static void prp_remove(struct imx_ic_priv *ic_priv)
501 {
502 	struct prp_priv *priv = ic_priv->task_priv;
503 
504 	mutex_destroy(&priv->lock);
505 }
506 
507 struct imx_ic_ops imx_ic_prp_ops = {
508 	.subdev_ops = &prp_subdev_ops,
509 	.internal_ops = &prp_internal_ops,
510 	.entity_ops = &prp_entity_ops,
511 	.init = prp_init,
512 	.remove = prp_remove,
513 };
514