xref: /linux/drivers/staging/media/imx/imx-ic-prp.c (revision 44f57d78)
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       176
30 #define MIN_H       144
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_media_dev *md;
39 	struct imx_ic_priv *ic_priv;
40 	struct media_pad pad[PRP_NUM_PADS];
41 
42 	/* lock to protect all members below */
43 	struct mutex lock;
44 
45 	/* IPU units we require */
46 	struct ipu_soc *ipu;
47 
48 	struct v4l2_subdev *src_sd;
49 	struct v4l2_subdev *sink_sd_prpenc;
50 	struct v4l2_subdev *sink_sd_prpvf;
51 
52 	/* the CSI id at link validate */
53 	int csi_id;
54 
55 	struct v4l2_mbus_framefmt format_mbus;
56 	struct v4l2_fract frame_interval;
57 
58 	int stream_count;
59 };
60 
61 static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
62 {
63 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
64 
65 	return ic_priv->prp_priv;
66 }
67 
68 static int prp_start(struct prp_priv *priv)
69 {
70 	struct imx_ic_priv *ic_priv = priv->ic_priv;
71 	bool src_is_vdic;
72 
73 	priv->ipu = priv->md->ipu[ic_priv->ipu_id];
74 
75 	/* set IC to receive from CSI or VDI depending on source */
76 	src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
77 
78 	ipu_set_ic_src_mux(priv->ipu, priv->csi_id, src_is_vdic);
79 
80 	return 0;
81 }
82 
83 static void prp_stop(struct prp_priv *priv)
84 {
85 }
86 
87 static struct v4l2_mbus_framefmt *
88 __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
89 	      unsigned int pad, enum v4l2_subdev_format_whence which)
90 {
91 	struct imx_ic_priv *ic_priv = priv->ic_priv;
92 
93 	if (which == V4L2_SUBDEV_FORMAT_TRY)
94 		return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
95 	else
96 		return &priv->format_mbus;
97 }
98 
99 /*
100  * V4L2 subdev operations.
101  */
102 
103 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
104 			      struct v4l2_subdev_pad_config *cfg,
105 			      struct v4l2_subdev_mbus_code_enum *code)
106 {
107 	struct prp_priv *priv = sd_to_priv(sd);
108 	struct v4l2_mbus_framefmt *infmt;
109 	int ret = 0;
110 
111 	mutex_lock(&priv->lock);
112 
113 	switch (code->pad) {
114 	case PRP_SINK_PAD:
115 		ret = imx_media_enum_ipu_format(&code->code, code->index,
116 						CS_SEL_ANY);
117 		break;
118 	case PRP_SRC_PAD_PRPENC:
119 	case PRP_SRC_PAD_PRPVF:
120 		if (code->index != 0) {
121 			ret = -EINVAL;
122 			goto out;
123 		}
124 		infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, code->which);
125 		code->code = infmt->code;
126 		break;
127 	default:
128 		ret = -EINVAL;
129 	}
130 out:
131 	mutex_unlock(&priv->lock);
132 	return ret;
133 }
134 
135 static int prp_get_fmt(struct v4l2_subdev *sd,
136 		       struct v4l2_subdev_pad_config *cfg,
137 		       struct v4l2_subdev_format *sdformat)
138 {
139 	struct prp_priv *priv = sd_to_priv(sd);
140 	struct v4l2_mbus_framefmt *fmt;
141 	int ret = 0;
142 
143 	if (sdformat->pad >= PRP_NUM_PADS)
144 		return -EINVAL;
145 
146 	mutex_lock(&priv->lock);
147 
148 	fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
149 	if (!fmt) {
150 		ret = -EINVAL;
151 		goto out;
152 	}
153 
154 	sdformat->format = *fmt;
155 out:
156 	mutex_unlock(&priv->lock);
157 	return ret;
158 }
159 
160 static int prp_set_fmt(struct v4l2_subdev *sd,
161 		       struct v4l2_subdev_pad_config *cfg,
162 		       struct v4l2_subdev_format *sdformat)
163 {
164 	struct prp_priv *priv = sd_to_priv(sd);
165 	struct v4l2_mbus_framefmt *fmt, *infmt;
166 	const struct imx_media_pixfmt *cc;
167 	int ret = 0;
168 	u32 code;
169 
170 	if (sdformat->pad >= PRP_NUM_PADS)
171 		return -EINVAL;
172 
173 	mutex_lock(&priv->lock);
174 
175 	if (priv->stream_count > 0) {
176 		ret = -EBUSY;
177 		goto out;
178 	}
179 
180 	infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which);
181 
182 	switch (sdformat->pad) {
183 	case PRP_SINK_PAD:
184 		v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
185 				      W_ALIGN, &sdformat->format.height,
186 				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
187 
188 		cc = imx_media_find_ipu_format(sdformat->format.code,
189 					       CS_SEL_ANY);
190 		if (!cc) {
191 			imx_media_enum_ipu_format(&code, 0, CS_SEL_ANY);
192 			cc = imx_media_find_ipu_format(code, CS_SEL_ANY);
193 			sdformat->format.code = cc->codes[0];
194 		}
195 
196 		imx_media_fill_default_mbus_fields(&sdformat->format, infmt,
197 						   true);
198 		break;
199 	case PRP_SRC_PAD_PRPENC:
200 	case PRP_SRC_PAD_PRPVF:
201 		/* Output pads mirror input pad */
202 		sdformat->format = *infmt;
203 		break;
204 	}
205 
206 	fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
207 	*fmt = sdformat->format;
208 out:
209 	mutex_unlock(&priv->lock);
210 	return ret;
211 }
212 
213 static int prp_link_setup(struct media_entity *entity,
214 			  const struct media_pad *local,
215 			  const struct media_pad *remote, u32 flags)
216 {
217 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
218 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
219 	struct prp_priv *priv = ic_priv->prp_priv;
220 	struct v4l2_subdev *remote_sd;
221 	int ret = 0;
222 
223 	dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
224 		local->entity->name);
225 
226 	remote_sd = media_entity_to_v4l2_subdev(remote->entity);
227 
228 	mutex_lock(&priv->lock);
229 
230 	if (local->flags & MEDIA_PAD_FL_SINK) {
231 		if (flags & MEDIA_LNK_FL_ENABLED) {
232 			if (priv->src_sd) {
233 				ret = -EBUSY;
234 				goto out;
235 			}
236 			if (priv->sink_sd_prpenc &&
237 			    (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) {
238 				ret = -EINVAL;
239 				goto out;
240 			}
241 			priv->src_sd = remote_sd;
242 		} else {
243 			priv->src_sd = NULL;
244 		}
245 
246 		goto out;
247 	}
248 
249 	/* this is a source pad */
250 	if (flags & MEDIA_LNK_FL_ENABLED) {
251 		switch (local->index) {
252 		case PRP_SRC_PAD_PRPENC:
253 			if (priv->sink_sd_prpenc) {
254 				ret = -EBUSY;
255 				goto out;
256 			}
257 			if (priv->src_sd && (priv->src_sd->grp_id &
258 					     IMX_MEDIA_GRP_ID_IPU_VDIC)) {
259 				ret = -EINVAL;
260 				goto out;
261 			}
262 			priv->sink_sd_prpenc = remote_sd;
263 			break;
264 		case PRP_SRC_PAD_PRPVF:
265 			if (priv->sink_sd_prpvf) {
266 				ret = -EBUSY;
267 				goto out;
268 			}
269 			priv->sink_sd_prpvf = remote_sd;
270 			break;
271 		default:
272 			ret = -EINVAL;
273 		}
274 	} else {
275 		switch (local->index) {
276 		case PRP_SRC_PAD_PRPENC:
277 			priv->sink_sd_prpenc = NULL;
278 			break;
279 		case PRP_SRC_PAD_PRPVF:
280 			priv->sink_sd_prpvf = NULL;
281 			break;
282 		default:
283 			ret = -EINVAL;
284 		}
285 	}
286 
287 out:
288 	mutex_unlock(&priv->lock);
289 	return ret;
290 }
291 
292 static int prp_link_validate(struct v4l2_subdev *sd,
293 			     struct media_link *link,
294 			     struct v4l2_subdev_format *source_fmt,
295 			     struct v4l2_subdev_format *sink_fmt)
296 {
297 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
298 	struct prp_priv *priv = ic_priv->prp_priv;
299 	struct v4l2_subdev *csi;
300 	int ret;
301 
302 	ret = v4l2_subdev_link_validate_default(sd, link,
303 						source_fmt, sink_fmt);
304 	if (ret)
305 		return ret;
306 
307 	csi = imx_media_find_upstream_subdev(priv->md, &ic_priv->sd.entity,
308 					     IMX_MEDIA_GRP_ID_IPU_CSI);
309 	if (IS_ERR(csi))
310 		csi = NULL;
311 
312 	mutex_lock(&priv->lock);
313 
314 	if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
315 		/*
316 		 * the ->PRPENC link cannot be enabled if the source
317 		 * is the VDIC
318 		 */
319 		if (priv->sink_sd_prpenc) {
320 			ret = -EINVAL;
321 			goto out;
322 		}
323 	} else {
324 		/* the source is a CSI */
325 		if (!csi) {
326 			ret = -EINVAL;
327 			goto out;
328 		}
329 	}
330 
331 	if (csi) {
332 		switch (csi->grp_id) {
333 		case IMX_MEDIA_GRP_ID_IPU_CSI0:
334 			priv->csi_id = 0;
335 			break;
336 		case IMX_MEDIA_GRP_ID_IPU_CSI1:
337 			priv->csi_id = 1;
338 			break;
339 		default:
340 			ret = -EINVAL;
341 		}
342 	} else {
343 		priv->csi_id = 0;
344 	}
345 
346 out:
347 	mutex_unlock(&priv->lock);
348 	return ret;
349 }
350 
351 static int prp_s_stream(struct v4l2_subdev *sd, int enable)
352 {
353 	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
354 	struct prp_priv *priv = ic_priv->prp_priv;
355 	int ret = 0;
356 
357 	mutex_lock(&priv->lock);
358 
359 	if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) {
360 		ret = -EPIPE;
361 		goto out;
362 	}
363 
364 	/*
365 	 * enable/disable streaming only if stream_count is
366 	 * going from 0 to 1 / 1 to 0.
367 	 */
368 	if (priv->stream_count != !enable)
369 		goto update_count;
370 
371 	dev_dbg(ic_priv->dev, "stream %s\n", 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 
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 
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 
434 /*
435  * retrieve our pads parsed from the OF graph by the media device
436  */
437 static int prp_registered(struct v4l2_subdev *sd)
438 {
439 	struct prp_priv *priv = sd_to_priv(sd);
440 	int i, ret;
441 	u32 code;
442 
443 	/* get media device */
444 	priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
445 
446 	for (i = 0; i < PRP_NUM_PADS; i++) {
447 		priv->pad[i].flags = (i == PRP_SINK_PAD) ?
448 			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
449 	}
450 
451 	/* init default frame interval */
452 	priv->frame_interval.numerator = 1;
453 	priv->frame_interval.denominator = 30;
454 
455 	/* set a default mbus format  */
456 	imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
457 	ret = imx_media_init_mbus_fmt(&priv->format_mbus, 640, 480, code,
458 				      V4L2_FIELD_NONE, NULL);
459 	if (ret)
460 		return ret;
461 
462 	return media_entity_pads_init(&sd->entity, PRP_NUM_PADS, priv->pad);
463 }
464 
465 static const struct v4l2_subdev_pad_ops prp_pad_ops = {
466 	.init_cfg = imx_media_init_cfg,
467 	.enum_mbus_code = prp_enum_mbus_code,
468 	.get_fmt = prp_get_fmt,
469 	.set_fmt = prp_set_fmt,
470 	.link_validate = prp_link_validate,
471 };
472 
473 static const struct v4l2_subdev_video_ops prp_video_ops = {
474 	.g_frame_interval = prp_g_frame_interval,
475 	.s_frame_interval = prp_s_frame_interval,
476 	.s_stream = prp_s_stream,
477 };
478 
479 static const struct media_entity_operations prp_entity_ops = {
480 	.link_setup = prp_link_setup,
481 	.link_validate = v4l2_subdev_link_validate,
482 };
483 
484 static const struct v4l2_subdev_ops prp_subdev_ops = {
485 	.video = &prp_video_ops,
486 	.pad = &prp_pad_ops,
487 };
488 
489 static const struct v4l2_subdev_internal_ops prp_internal_ops = {
490 	.registered = prp_registered,
491 };
492 
493 static int prp_init(struct imx_ic_priv *ic_priv)
494 {
495 	struct prp_priv *priv;
496 
497 	priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
498 	if (!priv)
499 		return -ENOMEM;
500 
501 	mutex_init(&priv->lock);
502 	ic_priv->prp_priv = priv;
503 	priv->ic_priv = ic_priv;
504 
505 	return 0;
506 }
507 
508 static void prp_remove(struct imx_ic_priv *ic_priv)
509 {
510 	struct prp_priv *priv = ic_priv->prp_priv;
511 
512 	mutex_destroy(&priv->lock);
513 }
514 
515 struct imx_ic_ops imx_ic_prp_ops = {
516 	.subdev_ops = &prp_subdev_ops,
517 	.internal_ops = &prp_internal_ops,
518 	.entity_ops = &prp_entity_ops,
519 	.init = prp_init,
520 	.remove = prp_remove,
521 };
522