On 30/08/17 13:49, Sakari Ailus wrote:
> This is the preferred way to parse the endpoints.
> 
> Comment rcar-vin as an example.
> 
> Signed-off-by: Sakari Ailus <sakari.ai...@linux.intel.com>
> ---
>  drivers/media/platform/rcar-vin/rcar-core.c | 111 
> ++++++++--------------------
>  drivers/media/platform/rcar-vin/rcar-dma.c  |  10 +--
>  drivers/media/platform/rcar-vin/rcar-v4l2.c |  14 ++--
>  drivers/media/platform/rcar-vin/rcar-vin.h  |   4 +-
>  drivers/media/v4l2-core/v4l2-fwnode.c       |  47 ++++++++++++
>  include/media/v4l2-fwnode.h                 |  49 ++++++++++++
>  6 files changed, 142 insertions(+), 93 deletions(-)
> 
> diff --git a/drivers/media/platform/rcar-vin/rcar-core.c 
> b/drivers/media/platform/rcar-vin/rcar-core.c
> index 142de447aaaa..4378806be1d4 100644
> --- a/drivers/media/platform/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/rcar-vin/rcar-core.c
> @@ -21,6 +21,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  
> +#include <media/v4l2-async.h>
>  #include <media/v4l2-fwnode.h>
>  
>  #include "rcar-vin.h"
> @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct 
> v4l2_async_notifier *notifier)
>       int ret;
>  
>       /* Verify subdevices mbus format */
> -     if (!rvin_mbus_supported(&vin->digital)) {
> +     if (!rvin_mbus_supported(vin->digital)) {
>               vin_err(vin, "Unsupported media bus format for %s\n",
> -                     vin->digital.subdev->name);
> +                     vin->digital->subdev->name);
>               return -EINVAL;
>       }
>  
>       vin_dbg(vin, "Found media bus format for %s: %d\n",
> -             vin->digital.subdev->name, vin->digital.code);
> +             vin->digital->subdev->name, vin->digital->code);
>  
>       ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
>       if (ret < 0) {
> @@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct 
> v4l2_async_notifier *notifier,
>  
>       vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
>       rvin_v4l2_remove(vin);
> -     vin->digital.subdev = NULL;
> +     vin->digital->subdev = NULL;
>  }
>  
>  static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
> @@ -120,117 +121,67 @@ static int rvin_digital_notify_bound(struct 
> v4l2_async_notifier *notifier,
>       ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
>       if (ret < 0)
>               return ret;
> -     vin->digital.source_pad = ret;
> +     vin->digital->source_pad = ret;
>  
>       ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
> -     vin->digital.sink_pad = ret < 0 ? 0 : ret;
> +     vin->digital->sink_pad = ret < 0 ? 0 : ret;
>  
> -     vin->digital.subdev = subdev;
> +     vin->digital->subdev = subdev;
>  
>       vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
> -             subdev->name, vin->digital.source_pad,
> -             vin->digital.sink_pad);
> +             subdev->name, vin->digital->source_pad,
> +             vin->digital->sink_pad);
>  
>       return 0;
>  }
>  
> -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
> -                                 struct device_node *ep,
> -                                 struct v4l2_mbus_config *mbus_cfg)
> +static int rvin_digital_parse_v4l2(struct device *dev,
> +                                struct v4l2_fwnode_endpoint *vep,
> +                                struct v4l2_async_subdev *asd)
>  {
> -     struct v4l2_fwnode_endpoint v4l2_ep;
> -     int ret;
> -
> -     ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
> -     if (ret) {
> -             vin_err(vin, "Could not parse v4l2 endpoint\n");
> -             return -EINVAL;
> -     }
> +     struct rvin_dev *vin = dev_get_drvdata(dev);
> +     struct rvin_graph_entity *rvge =
> +             container_of(asd, struct rvin_graph_entity, asd);
>  
> -     mbus_cfg->type = v4l2_ep.bus_type;
> +     rvge->mbus_cfg.type = vep->bus_type;
>  
> -     switch (mbus_cfg->type) {
> +     switch (rvge->mbus_cfg.type) {
>       case V4L2_MBUS_PARALLEL:
>               vin_dbg(vin, "Found PARALLEL media bus\n");
> -             mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
> +             rvge->mbus_cfg.flags = vep->bus.parallel.flags;
>               break;
>       case V4L2_MBUS_BT656:
>               vin_dbg(vin, "Found BT656 media bus\n");
> -             mbus_cfg->flags = 0;
> +             rvge->mbus_cfg.flags = 0;
>               break;
>       default:
>               vin_err(vin, "Unknown media bus type\n");
>               return -EINVAL;
>       }
>  
> -     return 0;
> -}
> -
> -static int rvin_digital_graph_parse(struct rvin_dev *vin)
> -{
> -     struct device_node *ep, *np;
> -     int ret;
> -
> -     vin->digital.asd.match.fwnode.fwnode = NULL;
> -     vin->digital.subdev = NULL;
> -
> -     /*
> -      * Port 0 id 0 is local digital input, try to get it.
> -      * Not all instances can or will have this, that is OK
> -      */
> -     ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
> -     if (!ep)
> -             return 0;
> -
> -     np = of_graph_get_remote_port_parent(ep);
> -     if (!np) {
> -             vin_err(vin, "No remote parent for digital input\n");
> -             of_node_put(ep);
> -             return -EINVAL;
> -     }
> -     of_node_put(np);
> -
> -     ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
> -     of_node_put(ep);
> -     if (ret)
> -             return ret;
> -
> -     vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
> -     vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> +     vin->digital = rvge;
>  
>       return 0;
>  }
>  
>  static int rvin_digital_graph_init(struct rvin_dev *vin)
>  {
> -     struct v4l2_async_subdev **subdevs = NULL;
>       int ret;
>  
> -     ret = rvin_digital_graph_parse(vin);
> +     ret = v4l2_async_notifier_parse_fwnode_endpoint(
> +             vin->dev, &vin->notifier, 0, 0,
> +             sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
>       if (ret)
>               return ret;
>  
> -     if (!vin->digital.asd.match.fwnode.fwnode) {
> -             vin_dbg(vin, "No digital subdevice found\n");
> -             return -ENODEV;
> -     }
> -
> -     /* Register the subdevices notifier. */
> -     subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
> -     if (subdevs == NULL)
> -             return -ENOMEM;
> +     if (vin->notifier.num_subdevs > 0)
> +             vin_dbg(vin, "Found digital subdevice %pOF\n",
> +                     to_of_node(
> +                             vin->notifier.subdevs[0]->match.fwnode.fwnode));
>  
> -     subdevs[0] = &vin->digital.asd;
> -
> -     vin_dbg(vin, "Found digital subdevice %pOF\n",
> -             to_of_node(subdevs[0]->match.fwnode.fwnode));
> -
> -     vin->notifier.num_subdevs = 1;
> -     vin->notifier.subdevs = subdevs;
>       vin->notifier.bound = rvin_digital_notify_bound;
>       vin->notifier.unbind = rvin_digital_notify_unbind;
>       vin->notifier.complete = rvin_digital_notify_complete;
> -
>       ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
>       if (ret < 0) {
>               vin_err(vin, "Notifier registration failed\n");
> @@ -290,6 +241,8 @@ static int rcar_vin_probe(struct platform_device *pdev)
>       if (ret)
>               return ret;
>  
> +     platform_set_drvdata(pdev, vin);
> +
>       ret = rvin_digital_graph_init(vin);
>       if (ret < 0)
>               goto error;
> @@ -297,11 +250,10 @@ static int rcar_vin_probe(struct platform_device *pdev)
>       pm_suspend_ignore_children(&pdev->dev, true);
>       pm_runtime_enable(&pdev->dev);
>  
> -     platform_set_drvdata(pdev, vin);
> -
>       return 0;
>  error:
>       rvin_dma_remove(vin);
> +     v4l2_async_notifier_release(&vin->notifier);
>  
>       return ret;
>  }
> @@ -313,6 +265,7 @@ static int rcar_vin_remove(struct platform_device *pdev)
>       pm_runtime_disable(&pdev->dev);
>  
>       v4l2_async_notifier_unregister(&vin->notifier);
> +     v4l2_async_notifier_release(&vin->notifier);
>  
>       rvin_dma_remove(vin);
>  
> diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c 
> b/drivers/media/platform/rcar-vin/rcar-dma.c
> index b136844499f6..23fdff7a7370 100644
> --- a/drivers/media/platform/rcar-vin/rcar-dma.c
> +++ b/drivers/media/platform/rcar-vin/rcar-dma.c
> @@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)
>       /*
>        * Input interface
>        */
> -     switch (vin->digital.code) {
> +     switch (vin->digital->code) {
>       case MEDIA_BUS_FMT_YUYV8_1X16:
>               /* BT.601/BT.1358 16bit YCbCr422 */
>               vnmc |= VNMC_INF_YUV16;
> @@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)
>               break;
>       case MEDIA_BUS_FMT_UYVY8_2X8:
>               /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
> -             vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
> +             vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
>                       VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
>               input_is_yuv = true;
>               break;
> @@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)
>               break;
>       case MEDIA_BUS_FMT_UYVY10_2X10:
>               /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
> -             vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
> +             vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
>                       VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
>               input_is_yuv = true;
>               break;
> @@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin)
>       dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
>  
>       /* Hsync Signal Polarity Select */
> -     if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
> +     if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
>               dmr2 |= VNDMR2_HPS;
>  
>       /* Vsync Signal Polarity Select */
> -     if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
> +     if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
>               dmr2 |= VNDMR2_VPS;
>  
>       /*
> diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c 
> b/drivers/media/platform/rcar-vin/rcar-v4l2.c
> index dd37ea811680..b479b882da12 100644
> --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
> +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
> @@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)
>       struct v4l2_mbus_framefmt *mf = &fmt.format;
>       int ret;
>  
> -     fmt.pad = vin->digital.source_pad;
> +     fmt.pad = vin->digital->source_pad;
>  
>       ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
>       if (ret)
> @@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev 
> *vin,
>  
>       sd = vin_to_source(vin);
>  
> -     v4l2_fill_mbus_format(&format.format, pix, vin->digital.code);
> +     v4l2_fill_mbus_format(&format.format, pix, vin->digital->code);
>  
>       pad_cfg = v4l2_subdev_alloc_pad_config(sd);
>       if (pad_cfg == NULL)
>               return -ENOMEM;
>  
> -     format.pad = vin->digital.source_pad;
> +     format.pad = vin->digital->source_pad;
>  
>       field = pix->field;
>  
> @@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void 
> *priv_fh,
>       if (timings->pad)
>               return -EINVAL;
>  
> -     timings->pad = vin->digital.sink_pad;
> +     timings->pad = vin->digital->sink_pad;
>  
>       ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
>  
> @@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void 
> *priv_fh,
>       if (cap->pad)
>               return -EINVAL;
>  
> -     cap->pad = vin->digital.sink_pad;
> +     cap->pad = vin->digital->sink_pad;
>  
>       ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
>  
> @@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, 
> struct v4l2_edid *edid)
>       if (edid->pad)
>               return -EINVAL;
>  
> -     edid->pad = vin->digital.sink_pad;
> +     edid->pad = vin->digital->sink_pad;
>  
>       ret = v4l2_subdev_call(sd, pad, get_edid, edid);
>  
> @@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, 
> struct v4l2_edid *edid)
>       if (edid->pad)
>               return -EINVAL;
>  
> -     edid->pad = vin->digital.sink_pad;
> +     edid->pad = vin->digital->sink_pad;
>  
>       ret = v4l2_subdev_call(sd, pad, set_edid, edid);
>  
> diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h 
> b/drivers/media/platform/rcar-vin/rcar-vin.h
> index 9bfb5a7c4dc4..5382078143fb 100644
> --- a/drivers/media/platform/rcar-vin/rcar-vin.h
> +++ b/drivers/media/platform/rcar-vin/rcar-vin.h
> @@ -126,7 +126,7 @@ struct rvin_dev {
>       struct v4l2_device v4l2_dev;
>       struct v4l2_ctrl_handler ctrl_handler;
>       struct v4l2_async_notifier notifier;
> -     struct rvin_graph_entity digital;
> +     struct rvin_graph_entity *digital;
>  
>       struct mutex lock;
>       struct vb2_queue queue;
> @@ -145,7 +145,7 @@ struct rvin_dev {
>       struct v4l2_rect compose;
>  };
>  
> -#define vin_to_source(vin)           vin->digital.subdev
> +#define vin_to_source(vin)           ((vin)->digital->subdev)
>  
>  /* Debug */
>  #define vin_dbg(d, fmt, arg...)              dev_dbg(d->dev, fmt, ##arg)
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c 
> b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 2496d76eef4b..4720e8a043cf 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -444,6 +444,53 @@ int v4l2_async_notifier_parse_fwnode_endpoints(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
>  
> +int v4l2_async_notifier_parse_fwnode_endpoint(
> +     struct device *dev, struct v4l2_async_notifier *notifier,
> +     unsigned int port_id, unsigned int endpoint_id, size_t asd_struct_size,
> +     int (*parse_single)(struct device *dev,
> +                         struct v4l2_fwnode_endpoint *vep,
> +                         struct v4l2_async_subdev *asd))
> +{
> +     struct fwnode_handle *fwnode = NULL;
> +     int ret;
> +
> +     while ((fwnode = fwnode_graph_get_next_endpoint(
> +                     dev_fwnode(dev), fwnode))) {
> +             struct fwnode_endpoint ep;
> +
> +             ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> +             if (ret < 0)
> +                     continue;
> +
> +             if (!fwnode_device_is_available(
> +                         fwnode_graph_get_port_parent(fwnode)))
> +                     continue;
> +
> +             if (ep.port == port_id && ep.id == endpoint_id)
> +                     break;
> +     }
> +
> +     if (!fwnode)
> +             return -ENOENT;
> +
> +     ret = v4l2_async_notifier_realloc(notifier, notifier->num_subdevs + 1);
> +     if (ret)
> +             goto out_err;
> +
> +     ret = v4l2_async_notifier_fwnode_parse_endpoint(
> +             dev, notifier, fwnode, asd_struct_size, parse_single);
> +     if (ret)
> +             goto out_err;
> +
> +     return 0;
> +
> +out_err:
> +     fwnode_handle_put(fwnode);
> +
> +     return ret;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoint);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ai...@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawro...@samsung.com>");
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index d063ab4ff67b..dd13604178b4 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -249,4 +249,53 @@ int v4l2_async_notifier_parse_fwnode_endpoints(
>                           struct v4l2_fwnode_endpoint *vep,
>                           struct v4l2_async_subdev *asd));
>  
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoint - Set up async notifier for an
> + *                                          fwnode based sub-device
> + * @dev: @struct device pointer
> + * @notifier: pointer to &struct v4l2_async_notifier
> + * @port_id: port number
> + * @endpoint_id: endpoint number
> + * @asd_struct_size: size of the driver's async sub-device struct, including
> + *                sizeof(struct v4l2_async_subdev). The &struct
> + *                v4l2_async_subdev shall be the first member of
> + *                the driver's async sub-device struct, i.e. both
> + *                begin at the same memory address.
> + * @parse_single: driver's callback function called on each V4L2 fwnode 
> endpoint
> + *
> + * Parse the fwnode endpoint of the @dev device corresponding to the given 
> port
> + * and endpoint numbres and populate the async sub- devices array of the

numbers
no space after sub-

> + * notifier. The @parse_endpoint callback function is called for the endpoint

parse_single, but (as in the previous patch) I actually prefer parse_endpoint.

> + * with the corresponding async sub-device pointer to let the caller 
> initialize
> + * the driver-specific part of the async sub-device structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on the
> + * notifier.

Should it? Doesn't this add additional subdevs?

I'm lost. What's the relationship between 
v4l2_async_notifier_parse_fwnode_endpoints
and this function? When do you use which? When you should zero the notifier?

Regards,

        Hans

> + *
> + * This function may not be called on a registered notifier and may be 
> called on
> + * a notifier once or more times, but may not be called more than once on a
> + * given port / endpoint pair. When using this function, the user may not 
> access
> + * the notifier's subdevs array nor change notifier's num_subdevs field, 
> these
> + * are reserved for the framework's internal use only.
> + *
> + * The @struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_single is released once the function is finished. If there is a 
> need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_release() after it has been unregistered and the async
> + * sub-devices are no longer in use.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + *      %-ENOMEM if memory allocation failed
> + *      %-EINVAL if graph or endpoint parsing failed
> + *      Other error codes as returned by @parse_single
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoint(
> +     struct device *dev, struct v4l2_async_notifier *notifier,
> +     unsigned int port_id, unsigned int endpoint_id, size_t asd_struct_size,
> +     int (*parse_single)(struct device *dev,
> +                         struct v4l2_fwnode_endpoint *vep,
> +                         struct v4l2_async_subdev *asd));
> +
>  #endif /* _V4L2_FWNODE_H */
> 

Reply via email to