Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 /*
0004  * Media Controller ancillary functions
0005  *
0006  * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@kernel.org>
0007  * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
0008  * Copyright (C) 2006-2010 Nokia Corporation
0009  * Copyright (c) 2016 Intel Corporation.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/pci.h>
0014 #include <linux/usb.h>
0015 #include <media/media-device.h>
0016 #include <media/media-entity.h>
0017 #include <media/v4l2-fh.h>
0018 #include <media/v4l2-mc.h>
0019 #include <media/v4l2-subdev.h>
0020 #include <media/videobuf2-core.h>
0021 
0022 int v4l2_mc_create_media_graph(struct media_device *mdev)
0023 
0024 {
0025     struct media_entity *entity;
0026     struct media_entity *if_vid = NULL, *if_aud = NULL;
0027     struct media_entity *tuner = NULL, *decoder = NULL;
0028     struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
0029     bool is_webcam = false;
0030     u32 flags;
0031     int ret, pad_sink, pad_source;
0032 
0033     if (!mdev)
0034         return 0;
0035 
0036     media_device_for_each_entity(entity, mdev) {
0037         switch (entity->function) {
0038         case MEDIA_ENT_F_IF_VID_DECODER:
0039             if_vid = entity;
0040             break;
0041         case MEDIA_ENT_F_IF_AUD_DECODER:
0042             if_aud = entity;
0043             break;
0044         case MEDIA_ENT_F_TUNER:
0045             tuner = entity;
0046             break;
0047         case MEDIA_ENT_F_ATV_DECODER:
0048             decoder = entity;
0049             break;
0050         case MEDIA_ENT_F_IO_V4L:
0051             io_v4l = entity;
0052             break;
0053         case MEDIA_ENT_F_IO_VBI:
0054             io_vbi = entity;
0055             break;
0056         case MEDIA_ENT_F_IO_SWRADIO:
0057             io_swradio = entity;
0058             break;
0059         case MEDIA_ENT_F_CAM_SENSOR:
0060             is_webcam = true;
0061             break;
0062         }
0063     }
0064 
0065     /* It should have at least one I/O entity */
0066     if (!io_v4l && !io_vbi && !io_swradio) {
0067         dev_warn(mdev->dev, "Didn't find any I/O entity\n");
0068         return -EINVAL;
0069     }
0070 
0071     /*
0072      * Here, webcams are modelled on a very simple way: the sensor is
0073      * connected directly to the I/O entity. All dirty details, like
0074      * scaler and crop HW are hidden. While such mapping is not enough
0075      * for mc-centric hardware, it is enough for v4l2 interface centric
0076      * PC-consumer's hardware.
0077      */
0078     if (is_webcam) {
0079         if (!io_v4l) {
0080             dev_warn(mdev->dev, "Didn't find a MEDIA_ENT_F_IO_V4L\n");
0081             return -EINVAL;
0082         }
0083 
0084         media_device_for_each_entity(entity, mdev) {
0085             if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
0086                 continue;
0087             ret = media_create_pad_link(entity, 0,
0088                             io_v4l, 0,
0089                             MEDIA_LNK_FL_ENABLED);
0090             if (ret) {
0091                 dev_warn(mdev->dev, "Failed to create a sensor link\n");
0092                 return ret;
0093             }
0094         }
0095         if (!decoder)
0096             return 0;
0097     }
0098 
0099     /* The device isn't a webcam. So, it should have a decoder */
0100     if (!decoder) {
0101         dev_warn(mdev->dev, "Decoder not found\n");
0102         return -EINVAL;
0103     }
0104 
0105     /* Link the tuner and IF video output pads */
0106     if (tuner) {
0107         if (if_vid) {
0108             pad_source = media_get_pad_index(tuner, false,
0109                              PAD_SIGNAL_ANALOG);
0110             pad_sink = media_get_pad_index(if_vid, true,
0111                                PAD_SIGNAL_ANALOG);
0112             if (pad_source < 0 || pad_sink < 0) {
0113                 dev_warn(mdev->dev, "Couldn't get tuner and/or PLL pad(s): (%d, %d)\n",
0114                      pad_source, pad_sink);
0115                 return -EINVAL;
0116             }
0117             ret = media_create_pad_link(tuner, pad_source,
0118                             if_vid, pad_sink,
0119                             MEDIA_LNK_FL_ENABLED);
0120             if (ret) {
0121                 dev_warn(mdev->dev, "Couldn't create tuner->PLL link)\n");
0122                 return ret;
0123             }
0124 
0125             pad_source = media_get_pad_index(if_vid, false,
0126                              PAD_SIGNAL_ANALOG);
0127             pad_sink = media_get_pad_index(decoder, true,
0128                                PAD_SIGNAL_ANALOG);
0129             if (pad_source < 0 || pad_sink < 0) {
0130                 dev_warn(mdev->dev, "get decoder and/or PLL pad(s): (%d, %d)\n",
0131                      pad_source, pad_sink);
0132                 return -EINVAL;
0133             }
0134             ret = media_create_pad_link(if_vid, pad_source,
0135                             decoder, pad_sink,
0136                             MEDIA_LNK_FL_ENABLED);
0137             if (ret) {
0138                 dev_warn(mdev->dev, "couldn't link PLL to decoder\n");
0139                 return ret;
0140             }
0141         } else {
0142             pad_source = media_get_pad_index(tuner, false,
0143                              PAD_SIGNAL_ANALOG);
0144             pad_sink = media_get_pad_index(decoder, true,
0145                                PAD_SIGNAL_ANALOG);
0146             if (pad_source < 0 || pad_sink < 0) {
0147                 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s): (%d, %d)\n",
0148                      pad_source, pad_sink);
0149                 return -EINVAL;
0150             }
0151             ret = media_create_pad_link(tuner, pad_source,
0152                             decoder, pad_sink,
0153                             MEDIA_LNK_FL_ENABLED);
0154             if (ret)
0155                 return ret;
0156         }
0157 
0158         if (if_aud) {
0159             pad_source = media_get_pad_index(tuner, false,
0160                              PAD_SIGNAL_AUDIO);
0161             pad_sink = media_get_pad_index(if_aud, true,
0162                                PAD_SIGNAL_AUDIO);
0163             if (pad_source < 0 || pad_sink < 0) {
0164                 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s) for audio: (%d, %d)\n",
0165                      pad_source, pad_sink);
0166                 return -EINVAL;
0167             }
0168             ret = media_create_pad_link(tuner, pad_source,
0169                             if_aud, pad_sink,
0170                             MEDIA_LNK_FL_ENABLED);
0171             if (ret) {
0172                 dev_warn(mdev->dev, "couldn't link tuner->audio PLL\n");
0173                 return ret;
0174             }
0175         } else {
0176             if_aud = tuner;
0177         }
0178 
0179     }
0180 
0181     /* Create demod to V4L, VBI and SDR radio links */
0182     if (io_v4l) {
0183         pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
0184         if (pad_source < 0) {
0185             dev_warn(mdev->dev, "couldn't get decoder output pad for V4L I/O\n");
0186             return -EINVAL;
0187         }
0188         ret = media_create_pad_link(decoder, pad_source,
0189                         io_v4l, 0,
0190                         MEDIA_LNK_FL_ENABLED);
0191         if (ret) {
0192             dev_warn(mdev->dev, "couldn't link decoder output to V4L I/O\n");
0193             return ret;
0194         }
0195     }
0196 
0197     if (io_swradio) {
0198         pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
0199         if (pad_source < 0) {
0200             dev_warn(mdev->dev, "couldn't get decoder output pad for SDR\n");
0201             return -EINVAL;
0202         }
0203         ret = media_create_pad_link(decoder, pad_source,
0204                         io_swradio, 0,
0205                         MEDIA_LNK_FL_ENABLED);
0206         if (ret) {
0207             dev_warn(mdev->dev, "couldn't link decoder output to SDR\n");
0208             return ret;
0209         }
0210     }
0211 
0212     if (io_vbi) {
0213         pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
0214         if (pad_source < 0) {
0215             dev_warn(mdev->dev, "couldn't get decoder output pad for VBI\n");
0216             return -EINVAL;
0217         }
0218         ret = media_create_pad_link(decoder, pad_source,
0219                         io_vbi, 0,
0220                         MEDIA_LNK_FL_ENABLED);
0221         if (ret) {
0222             dev_warn(mdev->dev, "couldn't link decoder output to VBI\n");
0223             return ret;
0224         }
0225     }
0226 
0227     /* Create links for the media connectors */
0228     flags = MEDIA_LNK_FL_ENABLED;
0229     media_device_for_each_entity(entity, mdev) {
0230         switch (entity->function) {
0231         case MEDIA_ENT_F_CONN_RF:
0232             if (!tuner)
0233                 continue;
0234             pad_sink = media_get_pad_index(tuner, true,
0235                                PAD_SIGNAL_ANALOG);
0236             if (pad_sink < 0) {
0237                 dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
0238                 return -EINVAL;
0239             }
0240             ret = media_create_pad_link(entity, 0, tuner,
0241                             pad_sink,
0242                             flags);
0243             break;
0244         case MEDIA_ENT_F_CONN_SVIDEO:
0245         case MEDIA_ENT_F_CONN_COMPOSITE:
0246             pad_sink = media_get_pad_index(decoder, true,
0247                                PAD_SIGNAL_ANALOG);
0248             if (pad_sink < 0) {
0249                 dev_warn(mdev->dev, "couldn't get decoder analog pad sink\n");
0250                 return -EINVAL;
0251             }
0252             ret = media_create_pad_link(entity, 0, decoder,
0253                             pad_sink,
0254                             flags);
0255             break;
0256         default:
0257             continue;
0258         }
0259         if (ret)
0260             return ret;
0261 
0262         flags = 0;
0263     }
0264 
0265     return 0;
0266 }
0267 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
0268 
0269 int v4l_enable_media_source(struct video_device *vdev)
0270 {
0271     struct media_device *mdev = vdev->entity.graph_obj.mdev;
0272     int ret = 0, err;
0273 
0274     if (!mdev)
0275         return 0;
0276 
0277     mutex_lock(&mdev->graph_mutex);
0278     if (!mdev->enable_source)
0279         goto end;
0280     err = mdev->enable_source(&vdev->entity, &vdev->pipe);
0281     if (err)
0282         ret = -EBUSY;
0283 end:
0284     mutex_unlock(&mdev->graph_mutex);
0285     return ret;
0286 }
0287 EXPORT_SYMBOL_GPL(v4l_enable_media_source);
0288 
0289 void v4l_disable_media_source(struct video_device *vdev)
0290 {
0291     struct media_device *mdev = vdev->entity.graph_obj.mdev;
0292 
0293     if (mdev) {
0294         mutex_lock(&mdev->graph_mutex);
0295         if (mdev->disable_source)
0296             mdev->disable_source(&vdev->entity);
0297         mutex_unlock(&mdev->graph_mutex);
0298     }
0299 }
0300 EXPORT_SYMBOL_GPL(v4l_disable_media_source);
0301 
0302 int v4l_vb2q_enable_media_source(struct vb2_queue *q)
0303 {
0304     struct v4l2_fh *fh = q->owner;
0305 
0306     if (fh && fh->vdev)
0307         return v4l_enable_media_source(fh->vdev);
0308     return 0;
0309 }
0310 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
0311 
0312 int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
0313                     struct media_pad *sink, u32 flags)
0314 {
0315     struct fwnode_handle *endpoint;
0316     struct v4l2_subdev *sink_sd;
0317 
0318     if (!(sink->flags & MEDIA_PAD_FL_SINK) ||
0319         !is_media_entity_v4l2_subdev(sink->entity))
0320         return -EINVAL;
0321 
0322     sink_sd = media_entity_to_v4l2_subdev(sink->entity);
0323 
0324     fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
0325         struct fwnode_handle *remote_ep;
0326         int src_idx, sink_idx, ret;
0327         struct media_pad *src;
0328 
0329         src_idx = media_entity_get_fwnode_pad(&src_sd->entity,
0330                               endpoint,
0331                               MEDIA_PAD_FL_SOURCE);
0332         if (src_idx < 0)
0333             continue;
0334 
0335         remote_ep = fwnode_graph_get_remote_endpoint(endpoint);
0336         if (!remote_ep)
0337             continue;
0338 
0339         /*
0340          * ask the sink to verify it owns the remote endpoint,
0341          * and translate to a sink pad.
0342          */
0343         sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity,
0344                                remote_ep,
0345                                MEDIA_PAD_FL_SINK);
0346         fwnode_handle_put(remote_ep);
0347 
0348         if (sink_idx < 0 || sink_idx != sink->index)
0349             continue;
0350 
0351         /*
0352          * the source endpoint corresponds to one of its source pads,
0353          * the source endpoint connects to an endpoint at the sink
0354          * entity, and the sink endpoint corresponds to the sink
0355          * pad requested, so we have found an endpoint connection
0356          * that works, create the media link for it.
0357          */
0358 
0359         src = &src_sd->entity.pads[src_idx];
0360 
0361         /* skip if link already exists */
0362         if (media_entity_find_link(src, sink))
0363             continue;
0364 
0365         dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n",
0366             src_sd->entity.name, src_idx,
0367             sink_sd->entity.name, sink_idx);
0368 
0369         ret = media_create_pad_link(&src_sd->entity, src_idx,
0370                         &sink_sd->entity, sink_idx, flags);
0371         if (ret) {
0372             dev_err(sink_sd->dev,
0373                 "link %s:%d -> %s:%d failed with %d\n",
0374                 src_sd->entity.name, src_idx,
0375                 sink_sd->entity.name, sink_idx, ret);
0376 
0377             fwnode_handle_put(endpoint);
0378             return ret;
0379         }
0380     }
0381 
0382     return 0;
0383 }
0384 EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad);
0385 
0386 int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
0387                  struct v4l2_subdev *sink_sd)
0388 {
0389     unsigned int i;
0390 
0391     for (i = 0; i < sink_sd->entity.num_pads; i++) {
0392         struct media_pad *pad = &sink_sd->entity.pads[i];
0393         int ret;
0394 
0395         if (!(pad->flags & MEDIA_PAD_FL_SINK))
0396             continue;
0397 
0398         ret = v4l2_create_fwnode_links_to_pad(src_sd, pad, 0);
0399         if (ret)
0400             return ret;
0401     }
0402 
0403     return 0;
0404 }
0405 EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);
0406 
0407 /* -----------------------------------------------------------------------------
0408  * Pipeline power management
0409  *
0410  * Entities must be powered up when part of a pipeline that contains at least
0411  * one open video device node.
0412  *
0413  * To achieve this use the entity use_count field to track the number of users.
0414  * For entities corresponding to video device nodes the use_count field stores
0415  * the users count of the node. For entities corresponding to subdevs the
0416  * use_count field stores the total number of users of all video device nodes
0417  * in the pipeline.
0418  *
0419  * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and
0420  * close() handlers of video device nodes. It increments or decrements the use
0421  * count of all subdev entities in the pipeline.
0422  *
0423  * To react to link management on powered pipelines, the link setup notification
0424  * callback updates the use count of all entities in the source and sink sides
0425  * of the link.
0426  */
0427 
0428 /*
0429  * pipeline_pm_use_count - Count the number of users of a pipeline
0430  * @entity: The entity
0431  *
0432  * Return the total number of users of all video device nodes in the pipeline.
0433  */
0434 static int pipeline_pm_use_count(struct media_entity *entity,
0435     struct media_graph *graph)
0436 {
0437     int use = 0;
0438 
0439     media_graph_walk_start(graph, entity);
0440 
0441     while ((entity = media_graph_walk_next(graph))) {
0442         if (is_media_entity_v4l2_video_device(entity))
0443             use += entity->use_count;
0444     }
0445 
0446     return use;
0447 }
0448 
0449 /*
0450  * pipeline_pm_power_one - Apply power change to an entity
0451  * @entity: The entity
0452  * @change: Use count change
0453  *
0454  * Change the entity use count by @change. If the entity is a subdev update its
0455  * power state by calling the core::s_power operation when the use count goes
0456  * from 0 to != 0 or from != 0 to 0.
0457  *
0458  * Return 0 on success or a negative error code on failure.
0459  */
0460 static int pipeline_pm_power_one(struct media_entity *entity, int change)
0461 {
0462     struct v4l2_subdev *subdev;
0463     int ret;
0464 
0465     subdev = is_media_entity_v4l2_subdev(entity)
0466            ? media_entity_to_v4l2_subdev(entity) : NULL;
0467 
0468     if (entity->use_count == 0 && change > 0 && subdev != NULL) {
0469         ret = v4l2_subdev_call(subdev, core, s_power, 1);
0470         if (ret < 0 && ret != -ENOIOCTLCMD)
0471             return ret;
0472     }
0473 
0474     entity->use_count += change;
0475     WARN_ON(entity->use_count < 0);
0476 
0477     if (entity->use_count == 0 && change < 0 && subdev != NULL)
0478         v4l2_subdev_call(subdev, core, s_power, 0);
0479 
0480     return 0;
0481 }
0482 
0483 /*
0484  * pipeline_pm_power - Apply power change to all entities in a pipeline
0485  * @entity: The entity
0486  * @change: Use count change
0487  *
0488  * Walk the pipeline to update the use count and the power state of all non-node
0489  * entities.
0490  *
0491  * Return 0 on success or a negative error code on failure.
0492  */
0493 static int pipeline_pm_power(struct media_entity *entity, int change,
0494     struct media_graph *graph)
0495 {
0496     struct media_entity *first = entity;
0497     int ret = 0;
0498 
0499     if (!change)
0500         return 0;
0501 
0502     media_graph_walk_start(graph, entity);
0503 
0504     while (!ret && (entity = media_graph_walk_next(graph)))
0505         if (is_media_entity_v4l2_subdev(entity))
0506             ret = pipeline_pm_power_one(entity, change);
0507 
0508     if (!ret)
0509         return ret;
0510 
0511     media_graph_walk_start(graph, first);
0512 
0513     while ((first = media_graph_walk_next(graph))
0514            && first != entity)
0515         if (is_media_entity_v4l2_subdev(first))
0516             pipeline_pm_power_one(first, -change);
0517 
0518     return ret;
0519 }
0520 
0521 static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use)
0522 {
0523     struct media_device *mdev = entity->graph_obj.mdev;
0524     int change = use ? 1 : -1;
0525     int ret;
0526 
0527     mutex_lock(&mdev->graph_mutex);
0528 
0529     /* Apply use count to node. */
0530     entity->use_count += change;
0531     WARN_ON(entity->use_count < 0);
0532 
0533     /* Apply power change to connected non-nodes. */
0534     ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
0535     if (ret < 0)
0536         entity->use_count -= change;
0537 
0538     mutex_unlock(&mdev->graph_mutex);
0539 
0540     return ret;
0541 }
0542 
0543 int v4l2_pipeline_pm_get(struct media_entity *entity)
0544 {
0545     return v4l2_pipeline_pm_use(entity, 1);
0546 }
0547 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get);
0548 
0549 void v4l2_pipeline_pm_put(struct media_entity *entity)
0550 {
0551     /* Powering off entities shouldn't fail. */
0552     WARN_ON(v4l2_pipeline_pm_use(entity, 0));
0553 }
0554 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put);
0555 
0556 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
0557                   unsigned int notification)
0558 {
0559     struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
0560     struct media_entity *source = link->source->entity;
0561     struct media_entity *sink = link->sink->entity;
0562     int source_use;
0563     int sink_use;
0564     int ret = 0;
0565 
0566     source_use = pipeline_pm_use_count(source, graph);
0567     sink_use = pipeline_pm_use_count(sink, graph);
0568 
0569     if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
0570         !(flags & MEDIA_LNK_FL_ENABLED)) {
0571         /* Powering off entities is assumed to never fail. */
0572         pipeline_pm_power(source, -sink_use, graph);
0573         pipeline_pm_power(sink, -source_use, graph);
0574         return 0;
0575     }
0576 
0577     if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
0578         (flags & MEDIA_LNK_FL_ENABLED)) {
0579 
0580         ret = pipeline_pm_power(source, sink_use, graph);
0581         if (ret < 0)
0582             return ret;
0583 
0584         ret = pipeline_pm_power(sink, source_use, graph);
0585         if (ret < 0)
0586             pipeline_pm_power(source, -sink_use, graph);
0587     }
0588 
0589     return ret;
0590 }
0591 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);