GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / staging / media / imx / imx-ic-prp.c
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
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
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
87 static void prp_stop(struct prp_priv *priv)
88 {
89 }
90
91 static struct v4l2_mbus_framefmt *
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
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
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
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
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
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
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
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
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  */
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
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
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 };