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