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
22int 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(source: entity, source_pad: 0,
88 sink: io_v4l, sink_pad: 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(entity: tuner,
109 MEDIA_PAD_FL_SOURCE,
110 sig_type: PAD_SIGNAL_ANALOG);
111 pad_sink = media_get_pad_index(entity: if_vid,
112 MEDIA_PAD_FL_SINK,
113 sig_type: 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(source: tuner, source_pad: pad_source,
120 sink: if_vid, sink_pad: 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(entity: if_vid,
128 MEDIA_PAD_FL_SOURCE,
129 sig_type: PAD_SIGNAL_ANALOG);
130 pad_sink = media_get_pad_index(entity: decoder,
131 MEDIA_PAD_FL_SINK,
132 sig_type: 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(source: if_vid, source_pad: pad_source,
139 sink: decoder, sink_pad: 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(entity: tuner,
147 MEDIA_PAD_FL_SOURCE,
148 sig_type: PAD_SIGNAL_ANALOG);
149 pad_sink = media_get_pad_index(entity: decoder,
150 MEDIA_PAD_FL_SINK,
151 sig_type: 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(source: tuner, source_pad: pad_source,
158 sink: decoder, sink_pad: 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(entity: tuner,
166 MEDIA_PAD_FL_SOURCE,
167 sig_type: PAD_SIGNAL_AUDIO);
168 pad_sink = media_get_pad_index(entity: if_aud,
169 MEDIA_PAD_FL_SINK,
170 sig_type: 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(source: tuner, source_pad: pad_source,
177 sink: if_aud, sink_pad: 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(entity: decoder, MEDIA_PAD_FL_SOURCE,
192 sig_type: 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(source: decoder, source_pad: pad_source,
198 sink: io_v4l, sink_pad: 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(entity: decoder, MEDIA_PAD_FL_SOURCE,
208 sig_type: 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(source: decoder, source_pad: pad_source,
214 sink: io_swradio, sink_pad: 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(entity: decoder, MEDIA_PAD_FL_SOURCE,
224 sig_type: 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(source: decoder, source_pad: pad_source,
230 sink: io_vbi, sink_pad: 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(entity: tuner, MEDIA_PAD_FL_SINK,
246 sig_type: 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(source: entity, source_pad: 0, sink: tuner,
252 sink_pad: 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(entity: decoder,
258 MEDIA_PAD_FL_SINK,
259 sig_type: 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(source: entity, source_pad: 0, sink: decoder,
265 sink_pad: 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}
279EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
280
281int 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;
295end:
296 mutex_unlock(lock: &mdev->graph_mutex);
297 return ret;
298}
299EXPORT_SYMBOL_GPL(v4l_enable_media_source);
300
301void 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(lock: &mdev->graph_mutex);
310 }
311}
312EXPORT_SYMBOL_GPL(v4l_disable_media_source);
313
314int 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}
322EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
323
324int 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(entity: &src_sd->entity,
338 fwnode: endpoint,
339 MEDIA_PAD_FL_SOURCE);
340 if (src_idx < 0) {
341 dev_dbg(src_sd->dev, "no source pad found for %pfw\n",
342 endpoint);
343 continue;
344 }
345
346 remote_ep = fwnode_graph_get_remote_endpoint(fwnode: endpoint);
347 if (!remote_ep) {
348 dev_dbg(src_sd->dev, "no remote ep found for %pfw\n",
349 endpoint);
350 continue;
351 }
352
353 /*
354 * ask the sink to verify it owns the remote endpoint,
355 * and translate to a sink pad.
356 */
357 sink_idx = media_entity_get_fwnode_pad(entity: sink->entity,
358 fwnode: remote_ep,
359 MEDIA_PAD_FL_SINK);
360 fwnode_handle_put(fwnode: remote_ep);
361
362 if (sink_idx < 0 || sink_idx != sink->index) {
363 dev_dbg(src_sd->dev,
364 "sink pad index mismatch or error (is %d, expected %u)\n",
365 sink_idx, sink->index);
366 continue;
367 }
368
369 /*
370 * the source endpoint corresponds to one of its source pads,
371 * the source endpoint connects to an endpoint at the sink
372 * entity, and the sink endpoint corresponds to the sink
373 * pad requested, so we have found an endpoint connection
374 * that works, create the media link for it.
375 */
376
377 src = &src_sd->entity.pads[src_idx];
378
379 /* skip if link already exists */
380 if (media_entity_find_link(source: src, sink)) {
381 dev_dbg(src_sd->dev,
382 "link %s:%d -> %s:%d already exists\n",
383 src_sd->entity.name, src_idx,
384 sink->entity->name, sink_idx);
385 continue;
386 }
387
388 dev_dbg(src_sd->dev, "creating link %s:%d -> %s:%d\n",
389 src_sd->entity.name, src_idx,
390 sink->entity->name, sink_idx);
391
392 ret = media_create_pad_link(source: &src_sd->entity, source_pad: src_idx,
393 sink: sink->entity, sink_pad: sink_idx, flags);
394 if (ret) {
395 dev_err(src_sd->dev,
396 "link %s:%d -> %s:%d failed with %d\n",
397 src_sd->entity.name, src_idx,
398 sink->entity->name, sink_idx, ret);
399
400 fwnode_handle_put(fwnode: endpoint);
401 return ret;
402 }
403 }
404
405 return 0;
406}
407EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad);
408
409int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
410 struct v4l2_subdev *sink_sd)
411{
412 unsigned int i;
413
414 for (i = 0; i < sink_sd->entity.num_pads; i++) {
415 struct media_pad *pad = &sink_sd->entity.pads[i];
416 int ret;
417
418 if (!(pad->flags & MEDIA_PAD_FL_SINK))
419 continue;
420
421 ret = v4l2_create_fwnode_links_to_pad(src_sd, pad, 0);
422 if (ret)
423 return ret;
424 }
425
426 return 0;
427}
428EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);
429
430/* -----------------------------------------------------------------------------
431 * Pipeline power management
432 *
433 * Entities must be powered up when part of a pipeline that contains at least
434 * one open video device node.
435 *
436 * To achieve this use the entity use_count field to track the number of users.
437 * For entities corresponding to video device nodes the use_count field stores
438 * the users count of the node. For entities corresponding to subdevs the
439 * use_count field stores the total number of users of all video device nodes
440 * in the pipeline.
441 *
442 * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and
443 * close() handlers of video device nodes. It increments or decrements the use
444 * count of all subdev entities in the pipeline.
445 *
446 * To react to link management on powered pipelines, the link setup notification
447 * callback updates the use count of all entities in the source and sink sides
448 * of the link.
449 */
450
451/*
452 * pipeline_pm_use_count - Count the number of users of a pipeline
453 * @entity: The entity
454 *
455 * Return the total number of users of all video device nodes in the pipeline.
456 */
457static int pipeline_pm_use_count(struct media_entity *entity,
458 struct media_graph *graph)
459{
460 int use = 0;
461
462 media_graph_walk_start(graph, entity);
463
464 while ((entity = media_graph_walk_next(graph))) {
465 if (is_media_entity_v4l2_video_device(entity))
466 use += entity->use_count;
467 }
468
469 return use;
470}
471
472/*
473 * pipeline_pm_power_one - Apply power change to an entity
474 * @entity: The entity
475 * @change: Use count change
476 *
477 * Change the entity use count by @change. If the entity is a subdev update its
478 * power state by calling the core::s_power operation when the use count goes
479 * from 0 to != 0 or from != 0 to 0.
480 *
481 * Return 0 on success or a negative error code on failure.
482 */
483static int pipeline_pm_power_one(struct media_entity *entity, int change)
484{
485 struct v4l2_subdev *subdev;
486 int ret;
487
488 subdev = is_media_entity_v4l2_subdev(entity)
489 ? media_entity_to_v4l2_subdev(entity) : NULL;
490
491 if (entity->use_count == 0 && change > 0 && subdev != NULL) {
492 ret = v4l2_subdev_call(subdev, core, s_power, 1);
493 if (ret < 0 && ret != -ENOIOCTLCMD)
494 return ret;
495 }
496
497 entity->use_count += change;
498 WARN_ON(entity->use_count < 0);
499
500 if (entity->use_count == 0 && change < 0 && subdev != NULL)
501 v4l2_subdev_call(subdev, core, s_power, 0);
502
503 return 0;
504}
505
506/*
507 * pipeline_pm_power - Apply power change to all entities in a pipeline
508 * @entity: The entity
509 * @change: Use count change
510 *
511 * Walk the pipeline to update the use count and the power state of all non-node
512 * entities.
513 *
514 * Return 0 on success or a negative error code on failure.
515 */
516static int pipeline_pm_power(struct media_entity *entity, int change,
517 struct media_graph *graph)
518{
519 struct media_entity *first = entity;
520 int ret = 0;
521
522 if (!change)
523 return 0;
524
525 media_graph_walk_start(graph, entity);
526
527 while (!ret && (entity = media_graph_walk_next(graph)))
528 if (is_media_entity_v4l2_subdev(entity))
529 ret = pipeline_pm_power_one(entity, change);
530
531 if (!ret)
532 return ret;
533
534 media_graph_walk_start(graph, entity: first);
535
536 while ((first = media_graph_walk_next(graph))
537 && first != entity)
538 if (is_media_entity_v4l2_subdev(entity: first))
539 pipeline_pm_power_one(entity: first, change: -change);
540
541 return ret;
542}
543
544static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use)
545{
546 struct media_device *mdev = entity->graph_obj.mdev;
547 int change = use ? 1 : -1;
548 int ret;
549
550 mutex_lock(&mdev->graph_mutex);
551
552 /* Apply use count to node. */
553 entity->use_count += change;
554 WARN_ON(entity->use_count < 0);
555
556 /* Apply power change to connected non-nodes. */
557 ret = pipeline_pm_power(entity, change, graph: &mdev->pm_count_walk);
558 if (ret < 0)
559 entity->use_count -= change;
560
561 mutex_unlock(lock: &mdev->graph_mutex);
562
563 return ret;
564}
565
566int v4l2_pipeline_pm_get(struct media_entity *entity)
567{
568 return v4l2_pipeline_pm_use(entity, use: 1);
569}
570EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get);
571
572void v4l2_pipeline_pm_put(struct media_entity *entity)
573{
574 /* Powering off entities shouldn't fail. */
575 WARN_ON(v4l2_pipeline_pm_use(entity, 0));
576}
577EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put);
578
579int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
580 unsigned int notification)
581{
582 struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
583 struct media_entity *source = link->source->entity;
584 struct media_entity *sink = link->sink->entity;
585 int source_use;
586 int sink_use;
587 int ret = 0;
588
589 source_use = pipeline_pm_use_count(entity: source, graph);
590 sink_use = pipeline_pm_use_count(entity: sink, graph);
591
592 if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
593 !(flags & MEDIA_LNK_FL_ENABLED)) {
594 /* Powering off entities is assumed to never fail. */
595 pipeline_pm_power(entity: source, change: -sink_use, graph);
596 pipeline_pm_power(entity: sink, change: -source_use, graph);
597 return 0;
598 }
599
600 if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
601 (flags & MEDIA_LNK_FL_ENABLED)) {
602
603 ret = pipeline_pm_power(entity: source, change: sink_use, graph);
604 if (ret < 0)
605 return ret;
606
607 ret = pipeline_pm_power(entity: sink, change: source_use, graph);
608 if (ret < 0)
609 pipeline_pm_power(entity: source, change: -sink_use, graph);
610 }
611
612 return ret;
613}
614EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);
615

source code of linux/drivers/media/v4l2-core/v4l2-mc.c