This source file includes following definitions.
- sd_to_priv
- prp_start
- prp_stop
- __prp_get_fmt
- prp_enum_mbus_code
- prp_get_fmt
- prp_set_fmt
- prp_link_setup
- prp_link_validate
- prp_s_stream
- prp_g_frame_interval
- prp_s_frame_interval
- prp_registered
- prp_init
- prp_remove
1
2
3
4
5
6
7
8
9
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
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
34 #define H_ALIGN 1
35 #define S_ALIGN 1
36
37 struct prp_priv {
38 struct imx_ic_priv *ic_priv;
39 struct media_pad pad[PRP_NUM_PADS];
40
41
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
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
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
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
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
77 static void prp_stop(struct prp_priv *priv)
78 {
79 }
80
81 static struct v4l2_mbus_framefmt *
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
95
96
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_format(&code->code, code->index,
110 CS_SEL_ANY);
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
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
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 CS_SEL_ANY);
184 if (!cc) {
185 imx_media_enum_ipu_format(&code, 0, CS_SEL_ANY);
186 cc = imx_media_find_ipu_format(code, CS_SEL_ANY);
187 sdformat->format.code = cc->codes[0];
188 }
189
190 if (sdformat->format.field == V4L2_FIELD_ANY)
191 sdformat->format.field = V4L2_FIELD_NONE;
192 break;
193 case PRP_SRC_PAD_PRPENC:
194 case PRP_SRC_PAD_PRPVF:
195
196 sdformat->format = *infmt;
197 break;
198 }
199
200 imx_media_try_colorimetry(&sdformat->format, true);
201
202 fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
203 *fmt = sdformat->format;
204 out:
205 mutex_unlock(&priv->lock);
206 return ret;
207 }
208
209 static int prp_link_setup(struct media_entity *entity,
210 const struct media_pad *local,
211 const struct media_pad *remote, u32 flags)
212 {
213 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
214 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
215 struct prp_priv *priv = ic_priv->task_priv;
216 struct v4l2_subdev *remote_sd;
217 int ret = 0;
218
219 dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
220 ic_priv->sd.name, remote->entity->name, local->entity->name);
221
222 remote_sd = media_entity_to_v4l2_subdev(remote->entity);
223
224 mutex_lock(&priv->lock);
225
226 if (local->flags & MEDIA_PAD_FL_SINK) {
227 if (flags & MEDIA_LNK_FL_ENABLED) {
228 if (priv->src_sd) {
229 ret = -EBUSY;
230 goto out;
231 }
232 if (priv->sink_sd_prpenc &&
233 (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) {
234 ret = -EINVAL;
235 goto out;
236 }
237 priv->src_sd = remote_sd;
238 } else {
239 priv->src_sd = NULL;
240 }
241
242 goto out;
243 }
244
245
246 if (flags & MEDIA_LNK_FL_ENABLED) {
247 switch (local->index) {
248 case PRP_SRC_PAD_PRPENC:
249 if (priv->sink_sd_prpenc) {
250 ret = -EBUSY;
251 goto out;
252 }
253 if (priv->src_sd && (priv->src_sd->grp_id &
254 IMX_MEDIA_GRP_ID_IPU_VDIC)) {
255 ret = -EINVAL;
256 goto out;
257 }
258 priv->sink_sd_prpenc = remote_sd;
259 break;
260 case PRP_SRC_PAD_PRPVF:
261 if (priv->sink_sd_prpvf) {
262 ret = -EBUSY;
263 goto out;
264 }
265 priv->sink_sd_prpvf = remote_sd;
266 break;
267 default:
268 ret = -EINVAL;
269 }
270 } else {
271 switch (local->index) {
272 case PRP_SRC_PAD_PRPENC:
273 priv->sink_sd_prpenc = NULL;
274 break;
275 case PRP_SRC_PAD_PRPVF:
276 priv->sink_sd_prpvf = NULL;
277 break;
278 default:
279 ret = -EINVAL;
280 }
281 }
282
283 out:
284 mutex_unlock(&priv->lock);
285 return ret;
286 }
287
288 static int prp_link_validate(struct v4l2_subdev *sd,
289 struct media_link *link,
290 struct v4l2_subdev_format *source_fmt,
291 struct v4l2_subdev_format *sink_fmt)
292 {
293 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
294 struct prp_priv *priv = ic_priv->task_priv;
295 struct v4l2_subdev *csi;
296 int ret;
297
298 ret = v4l2_subdev_link_validate_default(sd, link,
299 source_fmt, sink_fmt);
300 if (ret)
301 return ret;
302
303 csi = imx_media_pipeline_subdev(&ic_priv->sd.entity,
304 IMX_MEDIA_GRP_ID_IPU_CSI, true);
305 if (IS_ERR(csi))
306 csi = NULL;
307
308 mutex_lock(&priv->lock);
309
310 if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
311
312
313
314
315 if (priv->sink_sd_prpenc) {
316 ret = -EINVAL;
317 goto out;
318 }
319 } else {
320
321 if (!csi) {
322 ret = -EINVAL;
323 goto out;
324 }
325 }
326
327 if (csi) {
328 switch (csi->grp_id) {
329 case IMX_MEDIA_GRP_ID_IPU_CSI0:
330 priv->csi_id = 0;
331 break;
332 case IMX_MEDIA_GRP_ID_IPU_CSI1:
333 priv->csi_id = 1;
334 break;
335 default:
336 ret = -EINVAL;
337 }
338 } else {
339 priv->csi_id = 0;
340 }
341
342 out:
343 mutex_unlock(&priv->lock);
344 return ret;
345 }
346
347 static int prp_s_stream(struct v4l2_subdev *sd, int enable)
348 {
349 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
350 struct prp_priv *priv = ic_priv->task_priv;
351 int ret = 0;
352
353 mutex_lock(&priv->lock);
354
355 if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) {
356 ret = -EPIPE;
357 goto out;
358 }
359
360
361
362
363
364 if (priv->stream_count != !enable)
365 goto update_count;
366
367 dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
368 enable ? "ON" : "OFF");
369
370 if (enable)
371 ret = prp_start(priv);
372 else
373 prp_stop(priv);
374 if (ret)
375 goto out;
376
377
378 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
379 ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
380 if (ret) {
381 if (enable)
382 prp_stop(priv);
383 goto out;
384 }
385
386 update_count:
387 priv->stream_count += enable ? 1 : -1;
388 if (priv->stream_count < 0)
389 priv->stream_count = 0;
390 out:
391 mutex_unlock(&priv->lock);
392 return ret;
393 }
394
395 static int prp_g_frame_interval(struct v4l2_subdev *sd,
396 struct v4l2_subdev_frame_interval *fi)
397 {
398 struct prp_priv *priv = sd_to_priv(sd);
399
400 if (fi->pad >= PRP_NUM_PADS)
401 return -EINVAL;
402
403 mutex_lock(&priv->lock);
404 fi->interval = priv->frame_interval;
405 mutex_unlock(&priv->lock);
406
407 return 0;
408 }
409
410 static int prp_s_frame_interval(struct v4l2_subdev *sd,
411 struct v4l2_subdev_frame_interval *fi)
412 {
413 struct prp_priv *priv = sd_to_priv(sd);
414
415 if (fi->pad >= PRP_NUM_PADS)
416 return -EINVAL;
417
418 mutex_lock(&priv->lock);
419
420
421 if (fi->interval.numerator == 0 || fi->interval.denominator == 0)
422 fi->interval = priv->frame_interval;
423 else
424 priv->frame_interval = fi->interval;
425
426 mutex_unlock(&priv->lock);
427
428 return 0;
429 }
430
431
432
433
434 static int prp_registered(struct v4l2_subdev *sd)
435 {
436 struct prp_priv *priv = sd_to_priv(sd);
437 int i, ret;
438 u32 code;
439
440 for (i = 0; i < PRP_NUM_PADS; i++) {
441 priv->pad[i].flags = (i == PRP_SINK_PAD) ?
442 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
443 }
444
445
446 priv->frame_interval.numerator = 1;
447 priv->frame_interval.denominator = 30;
448
449
450 imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
451 ret = imx_media_init_mbus_fmt(&priv->format_mbus, 640, 480, code,
452 V4L2_FIELD_NONE, NULL);
453 if (ret)
454 return ret;
455
456 return media_entity_pads_init(&sd->entity, PRP_NUM_PADS, priv->pad);
457 }
458
459 static const struct v4l2_subdev_pad_ops prp_pad_ops = {
460 .init_cfg = imx_media_init_cfg,
461 .enum_mbus_code = prp_enum_mbus_code,
462 .get_fmt = prp_get_fmt,
463 .set_fmt = prp_set_fmt,
464 .link_validate = prp_link_validate,
465 };
466
467 static const struct v4l2_subdev_video_ops prp_video_ops = {
468 .g_frame_interval = prp_g_frame_interval,
469 .s_frame_interval = prp_s_frame_interval,
470 .s_stream = prp_s_stream,
471 };
472
473 static const struct media_entity_operations prp_entity_ops = {
474 .link_setup = prp_link_setup,
475 .link_validate = v4l2_subdev_link_validate,
476 };
477
478 static const struct v4l2_subdev_ops prp_subdev_ops = {
479 .video = &prp_video_ops,
480 .pad = &prp_pad_ops,
481 };
482
483 static const struct v4l2_subdev_internal_ops prp_internal_ops = {
484 .registered = prp_registered,
485 };
486
487 static int prp_init(struct imx_ic_priv *ic_priv)
488 {
489 struct prp_priv *priv;
490
491 priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
492 if (!priv)
493 return -ENOMEM;
494
495 mutex_init(&priv->lock);
496 ic_priv->task_priv = priv;
497 priv->ic_priv = ic_priv;
498
499 return 0;
500 }
501
502 static void prp_remove(struct imx_ic_priv *ic_priv)
503 {
504 struct prp_priv *priv = ic_priv->task_priv;
505
506 mutex_destroy(&priv->lock);
507 }
508
509 struct imx_ic_ops imx_ic_prp_ops = {
510 .subdev_ops = &prp_subdev_ops,
511 .internal_ops = &prp_internal_ops,
512 .entity_ops = &prp_entity_ops,
513 .init = prp_init,
514 .remove = prp_remove,
515 };