Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / staging / media / imx / imx-ic-prp.c
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_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
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         /* 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
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  * V4L2 subdev operations.
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                 /* Output pads mirror input pad */
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         /* this is a source pad */
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                  * the ->PRPENC link cannot be enabled if the source
313                  * is the VDIC
314                  */
315                 if (priv->sink_sd_prpenc) {
316                         ret = -EINVAL;
317                         goto out;
318                 }
319         } else {
320                 /* the source is a CSI */
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          * enable/disable streaming only if stream_count is
362          * going from 0 to 1 / 1 to 0.
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         /* start/stop upstream */
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         /* No limits on valid frame intervals */
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  * retrieve our pads parsed from the OF graph by the media device
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         /* init default frame interval */
446         priv->frame_interval.numerator = 1;
447         priv->frame_interval.denominator = 30;
448
449         /* set a default mbus format  */
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 };