GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / media / v4l2-core / v4l2-mc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4  * Media Controller ancillary functions
5  *
6  * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@kernel.org>
7  * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
8  * Copyright (C) 2006-2010 Nokia Corporation
9  * Copyright (c) 2016 Intel Corporation.
10  */
11
12 #include <linux/module.h>
13 #include <linux/pci.h>
14 #include <linux/usb.h>
15 #include <media/media-device.h>
16 #include <media/media-entity.h>
17 #include <media/v4l2-fh.h>
18 #include <media/v4l2-mc.h>
19 #include <media/v4l2-subdev.h>
20 #include <media/videobuf2-core.h>
21
22 int v4l2_mc_create_media_graph(struct media_device *mdev)
23
24 {
25         struct media_entity *entity;
26         struct media_entity *if_vid = NULL, *if_aud = NULL;
27         struct media_entity *tuner = NULL, *decoder = NULL;
28         struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
29         bool is_webcam = false;
30         u32 flags;
31         int ret, pad_sink, pad_source;
32
33         if (!mdev)
34                 return 0;
35
36         media_device_for_each_entity(entity, mdev) {
37                 switch (entity->function) {
38                 case MEDIA_ENT_F_IF_VID_DECODER:
39                         if_vid = entity;
40                         break;
41                 case MEDIA_ENT_F_IF_AUD_DECODER:
42                         if_aud = entity;
43                         break;
44                 case MEDIA_ENT_F_TUNER:
45                         tuner = entity;
46                         break;
47                 case MEDIA_ENT_F_ATV_DECODER:
48                         decoder = entity;
49                         break;
50                 case MEDIA_ENT_F_IO_V4L:
51                         io_v4l = entity;
52                         break;
53                 case MEDIA_ENT_F_IO_VBI:
54                         io_vbi = entity;
55                         break;
56                 case MEDIA_ENT_F_IO_SWRADIO:
57                         io_swradio = entity;
58                         break;
59                 case MEDIA_ENT_F_CAM_SENSOR:
60                         is_webcam = true;
61                         break;
62                 }
63         }
64
65         /* It should have at least one I/O entity */
66         if (!io_v4l && !io_vbi && !io_swradio) {
67                 dev_warn(mdev->dev, "Didn't find any I/O entity\n");
68                 return -EINVAL;
69         }
70
71         /*
72          * Here, webcams are modelled on a very simple way: the sensor is
73          * connected directly to the I/O entity. All dirty details, like
74          * scaler and crop HW are hidden. While such mapping is not enough
75          * for mc-centric hardware, it is enough for v4l2 interface centric
76          * PC-consumer's hardware.
77          */
78         if (is_webcam) {
79                 if (!io_v4l) {
80                         dev_warn(mdev->dev, "Didn't find a MEDIA_ENT_F_IO_V4L\n");
81                         return -EINVAL;
82                 }
83
84                 media_device_for_each_entity(entity, mdev) {
85                         if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
86                                 continue;
87                         ret = media_create_pad_link(entity, 0,
88                                                     io_v4l, 0,
89                                                     MEDIA_LNK_FL_ENABLED);
90                         if (ret) {
91                                 dev_warn(mdev->dev, "Failed to create a sensor link\n");
92                                 return ret;
93                         }
94                 }
95                 if (!decoder)
96                         return 0;
97         }
98
99         /* The device isn't a webcam. So, it should have a decoder */
100         if (!decoder) {
101                 dev_warn(mdev->dev, "Decoder not found\n");
102                 return -EINVAL;
103         }
104
105         /* Link the tuner and IF video output pads */
106         if (tuner) {
107                 if (if_vid) {
108                         pad_source = media_get_pad_index(tuner,
109                                                          MEDIA_PAD_FL_SOURCE,
110                                                          PAD_SIGNAL_ANALOG);
111                         pad_sink = media_get_pad_index(if_vid,
112                                                        MEDIA_PAD_FL_SINK,
113                                                        PAD_SIGNAL_ANALOG);
114                         if (pad_source < 0 || pad_sink < 0) {
115                                 dev_warn(mdev->dev, "Couldn't get tuner and/or PLL pad(s): (%d, %d)\n",
116                                          pad_source, pad_sink);
117                                 return -EINVAL;
118                         }
119                         ret = media_create_pad_link(tuner, pad_source,
120                                                     if_vid, pad_sink,
121                                                     MEDIA_LNK_FL_ENABLED);
122                         if (ret) {
123                                 dev_warn(mdev->dev, "Couldn't create tuner->PLL link)\n");
124                                 return ret;
125                         }
126
127                         pad_source = media_get_pad_index(if_vid,
128                                                          MEDIA_PAD_FL_SOURCE,
129                                                          PAD_SIGNAL_ANALOG);
130                         pad_sink = media_get_pad_index(decoder,
131                                                        MEDIA_PAD_FL_SINK,
132                                                        PAD_SIGNAL_ANALOG);
133                         if (pad_source < 0 || pad_sink < 0) {
134                                 dev_warn(mdev->dev, "get decoder and/or PLL pad(s): (%d, %d)\n",
135                                          pad_source, pad_sink);
136                                 return -EINVAL;
137                         }
138                         ret = media_create_pad_link(if_vid, pad_source,
139                                                     decoder, pad_sink,
140                                                     MEDIA_LNK_FL_ENABLED);
141                         if (ret) {
142                                 dev_warn(mdev->dev, "couldn't link PLL to decoder\n");
143                                 return ret;
144                         }
145                 } else {
146                         pad_source = media_get_pad_index(tuner,
147                                                          MEDIA_PAD_FL_SOURCE,
148                                                          PAD_SIGNAL_ANALOG);
149                         pad_sink = media_get_pad_index(decoder,
150                                                        MEDIA_PAD_FL_SINK,
151                                                        PAD_SIGNAL_ANALOG);
152                         if (pad_source < 0 || pad_sink < 0) {
153                                 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s): (%d, %d)\n",
154                                          pad_source, pad_sink);
155                                 return -EINVAL;
156                         }
157                         ret = media_create_pad_link(tuner, pad_source,
158                                                     decoder, pad_sink,
159                                                     MEDIA_LNK_FL_ENABLED);
160                         if (ret)
161                                 return ret;
162                 }
163
164                 if (if_aud) {
165                         pad_source = media_get_pad_index(tuner,
166                                                          MEDIA_PAD_FL_SOURCE,
167                                                          PAD_SIGNAL_AUDIO);
168                         pad_sink = media_get_pad_index(if_aud,
169                                                        MEDIA_PAD_FL_SINK,
170                                                        PAD_SIGNAL_AUDIO);
171                         if (pad_source < 0 || pad_sink < 0) {
172                                 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s) for audio: (%d, %d)\n",
173                                          pad_source, pad_sink);
174                                 return -EINVAL;
175                         }
176                         ret = media_create_pad_link(tuner, pad_source,
177                                                     if_aud, pad_sink,
178                                                     MEDIA_LNK_FL_ENABLED);
179                         if (ret) {
180                                 dev_warn(mdev->dev, "couldn't link tuner->audio PLL\n");
181                                 return ret;
182                         }
183                 } else {
184                         if_aud = tuner;
185                 }
186
187         }
188
189         /* Create demod to V4L, VBI and SDR radio links */
190         if (io_v4l) {
191                 pad_source = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE,
192                                                  PAD_SIGNAL_DV);
193                 if (pad_source < 0) {
194                         dev_warn(mdev->dev, "couldn't get decoder output pad for V4L I/O\n");
195                         return -EINVAL;
196                 }
197                 ret = media_create_pad_link(decoder, pad_source,
198                                             io_v4l, 0,
199                                             MEDIA_LNK_FL_ENABLED);
200                 if (ret) {
201                         dev_warn(mdev->dev, "couldn't link decoder output to V4L I/O\n");
202                         return ret;
203                 }
204         }
205
206         if (io_swradio) {
207                 pad_source = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE,
208                                                  PAD_SIGNAL_DV);
209                 if (pad_source < 0) {
210                         dev_warn(mdev->dev, "couldn't get decoder output pad for SDR\n");
211                         return -EINVAL;
212                 }
213                 ret = media_create_pad_link(decoder, pad_source,
214                                             io_swradio, 0,
215                                             MEDIA_LNK_FL_ENABLED);
216                 if (ret) {
217                         dev_warn(mdev->dev, "couldn't link decoder output to SDR\n");
218                         return ret;
219                 }
220         }
221
222         if (io_vbi) {
223                 pad_source = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE,
224                                                  PAD_SIGNAL_DV);
225                 if (pad_source < 0) {
226                         dev_warn(mdev->dev, "couldn't get decoder output pad for VBI\n");
227                         return -EINVAL;
228                 }
229                 ret = media_create_pad_link(decoder, pad_source,
230                                             io_vbi, 0,
231                                             MEDIA_LNK_FL_ENABLED);
232                 if (ret) {
233                         dev_warn(mdev->dev, "couldn't link decoder output to VBI\n");
234                         return ret;
235                 }
236         }
237
238         /* Create links for the media connectors */
239         flags = MEDIA_LNK_FL_ENABLED;
240         media_device_for_each_entity(entity, mdev) {
241                 switch (entity->function) {
242                 case MEDIA_ENT_F_CONN_RF:
243                         if (!tuner)
244                                 continue;
245                         pad_sink = media_get_pad_index(tuner, MEDIA_PAD_FL_SINK,
246                                                        PAD_SIGNAL_ANALOG);
247                         if (pad_sink < 0) {
248                                 dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
249                                 return -EINVAL;
250                         }
251                         ret = media_create_pad_link(entity, 0, tuner,
252                                                     pad_sink,
253                                                     flags);
254                         break;
255                 case MEDIA_ENT_F_CONN_SVIDEO:
256                 case MEDIA_ENT_F_CONN_COMPOSITE:
257                         pad_sink = media_get_pad_index(decoder,
258                                                        MEDIA_PAD_FL_SINK,
259                                                        PAD_SIGNAL_ANALOG);
260                         if (pad_sink < 0) {
261                                 dev_warn(mdev->dev, "couldn't get decoder analog pad sink\n");
262                                 return -EINVAL;
263                         }
264                         ret = media_create_pad_link(entity, 0, decoder,
265                                                     pad_sink,
266                                                     flags);
267                         break;
268                 default:
269                         continue;
270                 }
271                 if (ret)
272                         return ret;
273
274                 flags = 0;
275         }
276
277         return 0;
278 }
279 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
280
281 int v4l_enable_media_source(struct video_device *vdev)
282 {
283         struct media_device *mdev = vdev->entity.graph_obj.mdev;
284         int ret = 0, err;
285
286         if (!mdev)
287                 return 0;
288
289         mutex_lock(&mdev->graph_mutex);
290         if (!mdev->enable_source)
291                 goto end;
292         err = mdev->enable_source(&vdev->entity, &vdev->pipe);
293         if (err)
294                 ret = -EBUSY;
295 end:
296         mutex_unlock(&mdev->graph_mutex);
297         return ret;
298 }
299 EXPORT_SYMBOL_GPL(v4l_enable_media_source);
300
301 void v4l_disable_media_source(struct video_device *vdev)
302 {
303         struct media_device *mdev = vdev->entity.graph_obj.mdev;
304
305         if (mdev) {
306                 mutex_lock(&mdev->graph_mutex);
307                 if (mdev->disable_source)
308                         mdev->disable_source(&vdev->entity);
309                 mutex_unlock(&mdev->graph_mutex);
310         }
311 }
312 EXPORT_SYMBOL_GPL(v4l_disable_media_source);
313
314 int v4l_vb2q_enable_media_source(struct vb2_queue *q)
315 {
316         struct v4l2_fh *fh = q->owner;
317
318         if (fh && fh->vdev)
319                 return v4l_enable_media_source(fh->vdev);
320         return 0;
321 }
322 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
323
324 int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
325                                     struct media_pad *sink, u32 flags)
326 {
327         struct fwnode_handle *endpoint;
328
329         if (!(sink->flags & MEDIA_PAD_FL_SINK))
330                 return -EINVAL;
331
332         fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
333                 struct fwnode_handle *remote_ep;
334                 int src_idx, sink_idx, ret;
335                 struct media_pad *src;
336
337                 src_idx = media_entity_get_fwnode_pad(&src_sd->entity,
338                                                       endpoint,
339                                                       MEDIA_PAD_FL_SOURCE);
340                 if (src_idx < 0)
341                         continue;
342
343                 remote_ep = fwnode_graph_get_remote_endpoint(endpoint);
344                 if (!remote_ep)
345                         continue;
346
347                 /*
348                  * ask the sink to verify it owns the remote endpoint,
349                  * and translate to a sink pad.
350                  */
351                 sink_idx = media_entity_get_fwnode_pad(sink->entity,
352                                                        remote_ep,
353                                                        MEDIA_PAD_FL_SINK);
354                 fwnode_handle_put(remote_ep);
355
356                 if (sink_idx < 0 || sink_idx != sink->index)
357                         continue;
358
359                 /*
360                  * the source endpoint corresponds to one of its source pads,
361                  * the source endpoint connects to an endpoint at the sink
362                  * entity, and the sink endpoint corresponds to the sink
363                  * pad requested, so we have found an endpoint connection
364                  * that works, create the media link for it.
365                  */
366
367                 src = &src_sd->entity.pads[src_idx];
368
369                 /* skip if link already exists */
370                 if (media_entity_find_link(src, sink))
371                         continue;
372
373                 dev_dbg(src_sd->dev, "creating link %s:%d -> %s:%d\n",
374                         src_sd->entity.name, src_idx,
375                         sink->entity->name, sink_idx);
376
377                 ret = media_create_pad_link(&src_sd->entity, src_idx,
378                                             sink->entity, sink_idx, flags);
379                 if (ret) {
380                         dev_err(src_sd->dev,
381                                 "link %s:%d -> %s:%d failed with %d\n",
382                                 src_sd->entity.name, src_idx,
383                                 sink->entity->name, sink_idx, ret);
384
385                         fwnode_handle_put(endpoint);
386                         return ret;
387                 }
388         }
389
390         return 0;
391 }
392 EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad);
393
394 int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
395                              struct v4l2_subdev *sink_sd)
396 {
397         unsigned int i;
398
399         for (i = 0; i < sink_sd->entity.num_pads; i++) {
400                 struct media_pad *pad = &sink_sd->entity.pads[i];
401                 int ret;
402
403                 if (!(pad->flags & MEDIA_PAD_FL_SINK))
404                         continue;
405
406                 ret = v4l2_create_fwnode_links_to_pad(src_sd, pad, 0);
407                 if (ret)
408                         return ret;
409         }
410
411         return 0;
412 }
413 EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);
414
415 /* -----------------------------------------------------------------------------
416  * Pipeline power management
417  *
418  * Entities must be powered up when part of a pipeline that contains at least
419  * one open video device node.
420  *
421  * To achieve this use the entity use_count field to track the number of users.
422  * For entities corresponding to video device nodes the use_count field stores
423  * the users count of the node. For entities corresponding to subdevs the
424  * use_count field stores the total number of users of all video device nodes
425  * in the pipeline.
426  *
427  * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and
428  * close() handlers of video device nodes. It increments or decrements the use
429  * count of all subdev entities in the pipeline.
430  *
431  * To react to link management on powered pipelines, the link setup notification
432  * callback updates the use count of all entities in the source and sink sides
433  * of the link.
434  */
435
436 /*
437  * pipeline_pm_use_count - Count the number of users of a pipeline
438  * @entity: The entity
439  *
440  * Return the total number of users of all video device nodes in the pipeline.
441  */
442 static int pipeline_pm_use_count(struct media_entity *entity,
443         struct media_graph *graph)
444 {
445         int use = 0;
446
447         media_graph_walk_start(graph, entity);
448
449         while ((entity = media_graph_walk_next(graph))) {
450                 if (is_media_entity_v4l2_video_device(entity))
451                         use += entity->use_count;
452         }
453
454         return use;
455 }
456
457 /*
458  * pipeline_pm_power_one - Apply power change to an entity
459  * @entity: The entity
460  * @change: Use count change
461  *
462  * Change the entity use count by @change. If the entity is a subdev update its
463  * power state by calling the core::s_power operation when the use count goes
464  * from 0 to != 0 or from != 0 to 0.
465  *
466  * Return 0 on success or a negative error code on failure.
467  */
468 static int pipeline_pm_power_one(struct media_entity *entity, int change)
469 {
470         struct v4l2_subdev *subdev;
471         int ret;
472
473         subdev = is_media_entity_v4l2_subdev(entity)
474                ? media_entity_to_v4l2_subdev(entity) : NULL;
475
476         if (entity->use_count == 0 && change > 0 && subdev != NULL) {
477                 ret = v4l2_subdev_call(subdev, core, s_power, 1);
478                 if (ret < 0 && ret != -ENOIOCTLCMD)
479                         return ret;
480         }
481
482         entity->use_count += change;
483         WARN_ON(entity->use_count < 0);
484
485         if (entity->use_count == 0 && change < 0 && subdev != NULL)
486                 v4l2_subdev_call(subdev, core, s_power, 0);
487
488         return 0;
489 }
490
491 /*
492  * pipeline_pm_power - Apply power change to all entities in a pipeline
493  * @entity: The entity
494  * @change: Use count change
495  *
496  * Walk the pipeline to update the use count and the power state of all non-node
497  * entities.
498  *
499  * Return 0 on success or a negative error code on failure.
500  */
501 static int pipeline_pm_power(struct media_entity *entity, int change,
502         struct media_graph *graph)
503 {
504         struct media_entity *first = entity;
505         int ret = 0;
506
507         if (!change)
508                 return 0;
509
510         media_graph_walk_start(graph, entity);
511
512         while (!ret && (entity = media_graph_walk_next(graph)))
513                 if (is_media_entity_v4l2_subdev(entity))
514                         ret = pipeline_pm_power_one(entity, change);
515
516         if (!ret)
517                 return ret;
518
519         media_graph_walk_start(graph, first);
520
521         while ((first = media_graph_walk_next(graph))
522                && first != entity)
523                 if (is_media_entity_v4l2_subdev(first))
524                         pipeline_pm_power_one(first, -change);
525
526         return ret;
527 }
528
529 static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use)
530 {
531         struct media_device *mdev = entity->graph_obj.mdev;
532         int change = use ? 1 : -1;
533         int ret;
534
535         mutex_lock(&mdev->graph_mutex);
536
537         /* Apply use count to node. */
538         entity->use_count += change;
539         WARN_ON(entity->use_count < 0);
540
541         /* Apply power change to connected non-nodes. */
542         ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
543         if (ret < 0)
544                 entity->use_count -= change;
545
546         mutex_unlock(&mdev->graph_mutex);
547
548         return ret;
549 }
550
551 int v4l2_pipeline_pm_get(struct media_entity *entity)
552 {
553         return v4l2_pipeline_pm_use(entity, 1);
554 }
555 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get);
556
557 void v4l2_pipeline_pm_put(struct media_entity *entity)
558 {
559         /* Powering off entities shouldn't fail. */
560         WARN_ON(v4l2_pipeline_pm_use(entity, 0));
561 }
562 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put);
563
564 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
565                               unsigned int notification)
566 {
567         struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
568         struct media_entity *source = link->source->entity;
569         struct media_entity *sink = link->sink->entity;
570         int source_use;
571         int sink_use;
572         int ret = 0;
573
574         source_use = pipeline_pm_use_count(source, graph);
575         sink_use = pipeline_pm_use_count(sink, graph);
576
577         if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
578             !(flags & MEDIA_LNK_FL_ENABLED)) {
579                 /* Powering off entities is assumed to never fail. */
580                 pipeline_pm_power(source, -sink_use, graph);
581                 pipeline_pm_power(sink, -source_use, graph);
582                 return 0;
583         }
584
585         if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
586                 (flags & MEDIA_LNK_FL_ENABLED)) {
587
588                 ret = pipeline_pm_power(source, sink_use, graph);
589                 if (ret < 0)
590                         return ret;
591
592                 ret = pipeline_pm_power(sink, source_use, graph);
593                 if (ret < 0)
594                         pipeline_pm_power(source, -sink_use, graph);
595         }
596
597         return ret;
598 }
599 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);