Rework V4L2 fwnode parsing; add defaults and avoid iteration
Subsystems (15)
Sakari Ailus
maintainercover Rework V4L2 fwnode parsing; add defaults and avoid iteration
Hi folks,
This patchset reworks V4L2 fwnode endpoint parsing. It enables the use of endpoint configuration defaults that is available sensors and other drivers that only use a single endpoint. Well, the functionality was available already but no driver used it likely because of two reasons:
lack of any examples in a non-trivial problem area as well as lack of a needed functionality to obtain through non-iterative means in the fwnode graph API. Also the fwnode framework did not provide the most convenient APIs to perform this for drivers.
Conversion from the iterative API is done for the omap3isp and ipu3-cio2 drivers. A downside here is that this adds code: what used to be done in the framework in a one-size-fits-all fashion is now the responsibility of the driver. The benefits (default settings and simplicity of the implementation from driver's point of view) are not really achievable without some of that.
Also baked in the set is matching devices with endpoints by endpoint node rather than the device's node. This allows finding out more information than just the device bound (i.e. the port --- or endpoint --- through which it was bound). Compatibility support is provided for existing drivers by setting the fwnode to be matched based on the available endpoints. Drivers that use the async non-notifier API and have multiple ports will likely need special care and this is right now missing from the set, hence this is RFC for now.
The set depends on a few other patches. They all can be found here:
<URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=fwnode-linear>
since RFC v1:
- Add another patch to change fwnode refcounting for v4l2_async_notifier_add_fwnode_subdev
- Add a patch to fix OF node refcounting and use / put order for davinci-vpif
- Don't take endpoint reference in v4l2_async_register_subdev; that's not intended
- Fix kerneldoc documentation for
v4l2_async_notifier_add_fwnode_remote_subdev
- Fix endpoint refcounting in the patch changing fwnode parsing for the omap3isp driver
- Fixed a compiler error in rcar_drif.c --- thanks, Niklas!
Sakari Ailus (9):
davinci-vpif: Don't dereference endpoint after putting it, fix
refcounting
v4l2-async: Use endpoint node, not device node, for fwnode match
v4l2-async: Get fwnode reference when putting it to the notifier's
list
v4l2-async: Add v4l2_async_notifier_add_fwnode_remote_subdev
omap3isp: Rework OF endpoint parsing
v4l2-async: Safely clean up an uninitialised notifier
ipu3-cio2: Clean up notifier's subdev list if parsing endpoints fails
ipu3-cio2: Proceed with notifier init even if there are no subdevs
ipu3-cio2: Parse information from firmware without using callbacks
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 96 ++++---- drivers/media/platform/am437x/am437x-vpfe.c | 7 +- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 37 +-- drivers/media/platform/exynos4-is/media-dev.c | 14 +- drivers/media/platform/omap3isp/isp.c | 331 +++++++++++++++----------- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 10 +- drivers/media/platform/rcar_drif.c | 2 +- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 15 +- drivers/media/v4l2-core/v4l2-async.c | 37 ++- drivers/media/v4l2-core/v4l2-fwnode.c | 26 +- drivers/staging/media/soc_camera/soc_camera.c | 14 +- include/media/v4l2-async.h | 30 ++- 19 files changed, 386 insertions(+), 247 deletions(-)
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 1/9 davinci-vpif: Don't dereference endpoint after putting it, fix refcounting
The davinci-vpif driver dereferences its local endpoints after releasing the reference to them.
The driver also puts its endpoints explicitly while the of_graph_get_next_endpoint() does that, too, leading to obtaining a reference once and releasing it twice.
Both are fixed by this patch.
--- drivers/media/platform/davinci/vpif_capture.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/media/platform/davinci/vpif_capture.c +2 -3
@@ -1555,7 +1555,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (!rem) {dev_dbg (&pdev->dev,"Remote device at %pOF not found\n" , endpoint); -of_node_put (endpoint); goto done; }
@@ -1567,7 +1566,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) GFP_KERNEL);if (!chan->inputs) {of_node_put (rem); -of_node_put (endpoint); goto err_cleanup; }
@@ -1578,7 +1576,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) err =v4l2_fwnode_endpoint_parse (of_fwnode_handle (endpoint), &bus_cfg); -of_node_put (endpoint);if (err) {dev_err (&pdev->dev,"Could not parse the endpoint\n" );of_node_put (rem);
@@ -1609,6 +1606,7 @@ vpif_capture_get_pdata(struct platform_device *pdev) } done: +of_node_put (endpoint); pdata->asd_sizes[0 ] = i; pdata->subdev_count = i; pdata->card_name ="DA850/OMAP-L138 Video Capture" ;
@@ -1616,6 +1614,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)return pdata; err_cleanup: +of_node_put (endpoint);v4l2_async_notifier_cleanup (&vpif_obj.notifier);return NULL ;
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 1/9 davinci-vpif: Fix endpoint refcounting
In reply to Sakari AilusThis patch addresses two problems with endpoint refcounting in parsing davinci-vpif endpoints:
- put endpoints on error and
- do not dereference endpoints after they have been put.
--- drivers/media/platform/davinci/vpif_capture.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/media/platform/davinci/vpif_capture.c +2 -3
@@ -1555,7 +1555,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (!rem) {dev_dbg (&pdev->dev,"Remote device at %pOF not found\n" , endpoint); -of_node_put (endpoint); goto done; }
@@ -1567,7 +1566,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) GFP_KERNEL);if (!chan->inputs) {of_node_put (rem); -of_node_put (endpoint); goto err_cleanup; }
@@ -1578,7 +1576,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) err =v4l2_fwnode_endpoint_parse (of_fwnode_handle (endpoint), &bus_cfg); -of_node_put (endpoint);if (err) {dev_err (&pdev->dev,"Could not parse the endpoint\n" );of_node_put (rem);
@@ -1609,6 +1606,7 @@ vpif_capture_get_pdata(struct platform_device *pdev) } done: +of_node_put (endpoint); pdata->asd_sizes[0 ] = i; pdata->subdev_count = i; pdata->card_name ="DA850/OMAP-L138 Video Capture" ;
@@ -1616,6 +1614,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)return pdata; err_cleanup: +of_node_put (endpoint);v4l2_async_notifier_cleanup (&vpif_obj.notifier);return NULL ;
Signature · 1 line
2.11.0
Re: [PATCH 1/9] davinci-vpif: Fix endpoint refcounting
Hi Sakari,
My mail client at least is showing two versions of patch [1/9] with different commit messages but (I think) the same content.
Regards,
Ian
Quoted 57 lines · Sakari Ailus
This patch addresses two problems with endpoint refcounting in parsing davinci-vpif endpoints:
- put endpoints on error and
- do not dereference endpoints after they have been put.
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/platform/davinci/vpif_capture.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)drivers/media/platform/davinci/vpif_capture.c +2
-3@@ -1555,7 +1555,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (!rem) {dev_dbg (&pdev->dev,"Remote device at %pOF not found\n" , endpoint); -of_node_put (endpoint); goto done; }@@ -1567,7 +1566,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) GFP_KERNEL);if (!chan->inputs) {of_node_put (rem); -of_node_put (endpoint); goto err_cleanup; }@@ -1578,7 +1576,6 @@ vpif_capture_get_pdata(struct platform_device *pdev) err =v4l2_fwnode_endpoint_parse (of_fwnode_handle (endpoint), &bus_cfg); -of_node_put (endpoint);if (err) {dev_err (&pdev->dev,"Could not parse the endpoint\n" );of_node_put (rem);@@ -1609,6 +1606,7 @@ vpif_capture_get_pdata(struct platform_device *pdev) } done: +of_node_put (endpoint); pdata->asd_sizes[0 ] = i; pdata->subdev_count = i; pdata->card_name ="DA850/OMAP-L138 Video Capture" ;@@ -1616,6 +1614,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)return pdata; err_cleanup: +of_node_put (endpoint);v4l2_async_notifier_cleanup (&vpif_obj.notifier);return NULL ;
Sakari Ailus
maintainerRe: [PATCH 1/9] davinci-vpif: Fix endpoint refcounting
Hi Ian,
Quoted 4 lines · Ian Arkver
Hi Sakari,
My mail client at least is showing two versions of patch [1/9] with different commit messages but (I think) the same content.
Thanks for spotting this. I used the same output directory for git format-patch after changing the commit message. Oh well.
The other one is what I intended to send; please ignore this one.
Signature · 2 lines
Sakari Ailus [email protected]
Sakari Ailus
maintainerPATCH 2/9 v4l2-async: Use endpoint node, not device node, for fwnode match
In reply to Sakari AilusV4L2 async framework can use both device's fwnode and endpoints's fwnode for matching the async sub-device with the sub-device. In order to proceed moving towards endpoint matching assign the endpoint to the async sub-device.
As most async sub-device drivers (and the related hardware) only supports a single endpoint, use the first endpoint found. This works for all current drivers --- we only ever supported a single async sub-device per device to begin with.
For async devices that have no endpoints, continue to use the fwnode related to the device. This includes e.g. lens devices.
Depends-on: ("pxa-camera: Match with device node, not the port node")
--- drivers/media/platform/am437x/am437x-vpfe.c | 2 +- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 20 +++++++++++++++----- drivers/media/platform/exynos4-is/media-dev.c | 14 ++++++++++---- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 10 +++++----- drivers/media/platform/rcar_drif.c | 2 +- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 13 ++++++++++--- drivers/media/v4l2-core/v4l2-async.c | 9 +++++++-- drivers/media/v4l2-core/v4l2-fwnode.c | 2 +- drivers/staging/media/soc_camera/soc_camera.c | 14 ++++++++------ 16 files changed, 65 insertions(+), 35 deletions(-)
drivers/media/platform/am437x/am437x-vpfe.c +1 -1
@@ -2495,7 +2495,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe)if (flags &V4L2_MBUS_VSYNC_ACTIVE_HIGH ) sdinfo->vpfe_param.vdpol =1 ; - rem =of_graph_get_remote_port_parent (endpoint); + rem =of_graph_get_remote_endpoint (endpoint);if (!rem) {dev_err (dev,"Remote device at %pOF not found\n" , endpoint);
drivers/media/platform/atmel/atmel-isc.c +1 -1
@@ -2042,7 +2042,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)if (!epn)return 0 ; - rem =of_graph_get_remote_port_parent (epn); + rem =of_graph_get_remote_endpoint (epn);if (!rem) {dev_notice (dev,"Remote device at %pOF not found\n" , epn);
drivers/media/platform/atmel/atmel-isi.c +1 -1
@@ -1110,7 +1110,7 @@ static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)if (!ep)return -EINVAL ; - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (!remote)return -EINVAL ;
drivers/media/platform/cadence/cdns-csi2rx.c +1 -1
@@ -395,7 +395,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)return -EINVAL ; } - csi2rx->asd.match.fwnode =fwnode_graph_get_remote_port_parent (fwh); + csi2rx->asd.match.fwnode =fwnode_graph_get_remote_endpoint (fwh); csi2rx->asd.match_type =V4L2_ASYNC_MATCH_FWNODE ;of_node_put (ep);
drivers/media/platform/davinci/vpif_capture.c +15 -5
@@ -1542,7 +1542,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)for (i =0 ; i <VPIF_CAPTURE_NUM_CHANNELS ; i++) {struct v4l2_fwnode_endpoint bus_cfg = { .bus_type =0 }; -struct device_node *rem; +struct device_node *rem, *rem_ep;unsigned int flags;int err;
@@ -1551,13 +1551,22 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (!endpoint)break ; - rem =of_graph_get_remote_port_parent (endpoint); -if (!rem) { -dev_dbg (&pdev->dev,"Remote device at %pOF not found\n" , + rem_ep =of_graph_get_remote_endpoint (endpoint); +if (!rem_ep) { +dev_dbg (&pdev->dev,"Remote for endpoint %pOF not found\n" , endpoint); goto done; } + rem =of_graph_get_port_parent (rem_ep); +if (!rem) { +dev_dbg (&pdev->dev,"Remote endpoint at %pOF not found\n" , + rem_ep); +of_node_put (rem_ep); + goto done; + } +of_node_put (rem_ep); + sdinfo = &pdata->subdev_info[i]; chan = &pdata->chan_config[i]; chan->inputs = devm_kcalloc(&pdev->dev,
@@ -1597,12 +1606,13 @@ vpif_capture_get_pdata(struct platform_device *pdev) sdinfo->name = rem->full_name; pdata->asd[i] =v4l2_async_notifier_add_fwnode_subdev ( - &vpif_obj.notifier,of_fwnode_handle (rem), + &vpif_obj.notifier,of_fwnode_handle (rem_ep),sizeof (struct v4l2_async_subdev ));if (IS_ERR (pdata->asd[i])) {of_node_put (rem); goto err_cleanup; } + } done:
drivers/media/platform/exynos4-is/media-dev.c +10 -4
@@ -411,7 +411,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->mux_id = (endpoint.base.port -1 ) &0x1 ; - rem =of_graph_get_remote_port_parent (ep); + rem =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (rem ==NULL ) { v4l2_info(&fmd->v4l2_dev, "Remote device at %pOF not found\n",
@@ -1372,11 +1372,17 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,int i;/* Find platform data for this sensor subdev */ -for (i =0 ; i <ARRAY_SIZE (fmd->sensor); i++) -if (fmd->sensor[i].asd.match.fwnode == -of_fwnode_handle (subdev->dev->of_node)) +for (i =0 ; i <ARRAY_SIZE (fmd->sensor); i++) { +struct fwnode_handle *fwnode = +fwnode_graph_get_remote_port_parent (fmd->sensor[i].asd. + match.fwnode); + +if (fwnode ==of_fwnode_handle (subdev->dev->of_node)) si = &fmd->sensor[i]; +fwnode_handle_put (fwnode); + } +if (si ==NULL )return -EINVAL ;
drivers/media/platform/pxa_camera.c +1 -1
@@ -2350,7 +2350,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, pcdev->platform_flags |=PXA_CAMERA_PCLK_EN ; asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; - remote =of_graph_get_remote_port_parent (np); + remote =of_graph_get_remote_endpoint (np);if (remote) asd->match.fwnode =of_fwnode_handle (remote);else
drivers/media/platform/qcom/camss/camss.c +5 -5
@@ -466,7 +466,7 @@ static int camss_of_parse_ports(struct camss *camss) {struct device *dev = camss->dev;struct device_node *node =NULL ; -struct device_node *remote =NULL ; +struct fwnode_handle *remote =NULL ;int ret, num_subdevs =0 ;for_each_endpoint_of_node (dev->of_node, node) {
@@ -476,7 +476,8 @@ static int camss_of_parse_ports(struct camss *camss)if (!of_device_is_available (node))continue ; - remote =of_graph_get_remote_port_parent (node); + remote =fwnode_graph_get_remote_endpoint ( +of_fwnode_handle (node));if (!remote) {dev_err (dev,"Cannot get remote parent\n" ); ret = -EINVAL ;
@@ -484,11 +485,10 @@ static int camss_of_parse_ports(struct camss *camss) } asd =v4l2_async_notifier_add_fwnode_subdev ( - &camss->notifier,of_fwnode_handle (remote), -sizeof (*csd)); + &camss->notifier, remote,sizeof (*csd));if (IS_ERR (asd)) { ret =PTR_ERR (asd); -of_node_put (remote); +fwnode_handle_put (remote); goto err_cleanup; }
drivers/media/platform/rcar_drif.c +1 -1
@@ -1222,7 +1222,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)if (!ep)return 0 ; - fwnode =fwnode_graph_get_remote_port_parent (ep); + fwnode =fwnode_graph_get_remote_endpoint (ep);if (!fwnode) {dev_warn (sdr->dev,"bad remote port parent\n" );fwnode_handle_put (ep);
drivers/media/platform/renesas-ceu.c +1 -1
@@ -1581,7 +1581,7 @@ static int ceu_parse_dt(struct ceu_device *ceudev) ceu_sd = &ceudev->subdevs[i];INIT_LIST_HEAD (&ceu_sd->asd.list); - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep); ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; ceu_sd->asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; ceu_sd->asd.match.fwnode =of_fwnode_handle (remote);
drivers/media/platform/stm32/stm32-dcmi.c +1 -1
@@ -1592,7 +1592,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)if (!ep)return -EINVAL ; - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (!remote)return -EINVAL ;
drivers/media/platform/ti-vpe/cal.c +1 -1
@@ -1693,7 +1693,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) goto cleanup_exit; } - sensor_node =of_graph_get_remote_port_parent (ep_node); + sensor_node =of_graph_get_remote_endpoint (ep_node);if (!sensor_node) {ctx_dbg (3 , ctx,"can't get remote parent\n" ); goto cleanup_exit;
drivers/media/platform/xilinx/xilinx-vipp.c +10 -3
@@ -14,6 +14,7 @@#include <linux/of.h> #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/slab.h> #include <media/v4l2-async.h>
@@ -81,6 +82,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,dev_dbg (xdev->dev,"creating links for entity %s\n" , local->name);while (1 ) { +struct fwnode_handle *fwnode; +/* Get the next endpoint and parse its link. */ ep =fwnode_graph_get_next_endpoint (entity->asd.match.fwnode, ep);
@@ -116,11 +119,13 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,continue ; } + fwnode =fwnode_graph_get_port_parent (link.remote_node); +fwnode_handle_put (fwnode); +/* Skip DMA engines, they will be processed separately. */ -if (link.remote_node ==of_fwnode_handle (xdev->dev->of_node)) { +if (fwnode ==dev_fwnode (xdev->dev)) {dev_dbg (xdev->dev,"skipping DMA port %p:%u\n" , link.local_node, link.local_port); -v4l2_fwnode_put_link (&link);continue ; }
@@ -374,9 +379,11 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, }fwnode_handle_put (ep); + fwnode =fwnode_graph_get_port_parent (remote); +fwnode_handle_put (fwnode);/* Skip entities that we have already processed. */ -if (remote ==of_fwnode_handle (xdev->dev->of_node) || +if (fwnode ==dev_fwnode (xdev->dev) ||xvip_graph_find_entity (xdev, remote)) {fwnode_handle_put (remote);continue ;
drivers/media/v4l2-core/v4l2-async.c +7 -2
@@ -670,8 +670,13 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)* (struct v4l2_subdev.dev), and async sub-device does not * exist independently of the device at any point of time. */ -if (!sd->fwnode && sd->dev) - sd->fwnode =dev_fwnode (sd->dev); +if (!sd->fwnode && sd->dev) { + sd->fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (sd->dev),NULL ); +fwnode_handle_put (sd->fwnode); +if (!sd->fwnode) + sd->fwnode =dev_fwnode (sd->dev); + }mutex_lock (&list_lock);
drivers/media/v4l2-core/v4l2-fwnode.c +1 -1
@@ -617,7 +617,7 @@ v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; asd->match.fwnode = -fwnode_graph_get_remote_port_parent (endpoint); +fwnode_graph_get_remote_endpoint (endpoint);if (!asd->match.fwnode) {dev_dbg (dev,"no remote endpoint found\n" ); ret = -ENOTCONN ;
drivers/staging/media/soc_camera/soc_camera.c +8 -6
@@ -1518,6 +1518,7 @@ static int soc_of_bind(struct soc_camera_host *ici,struct soc_camera_async_client *sasc;struct soc_of_info *info;struct i2c_client *client; +struct device_node *np;char clk_name[V4L2_CLK_NAME_SIZE ];int ret;
@@ -1552,23 +1553,23 @@ static int soc_of_bind(struct soc_camera_host *ici,v4l2_async_notifier_init (&sasc->notifier); ret =v4l2_async_notifier_add_subdev (&sasc->notifier, info->subdev); -if (ret) { -of_node_put (remote); +if (ret) goto eaddasd; - } sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; + np =of_graph_get_port_parent (remote); +of_node_put (remote); - client =of_find_i2c_device_by_node (remote); + client =of_find_i2c_device_by_node (np);if (client)v4l2_clk_name_i2c (clk_name,sizeof (clk_name), client->adapter->nr, client->addr);else -v4l2_clk_name_of (clk_name,sizeof (clk_name), remote); +v4l2_clk_name_of (clk_name,sizeof (clk_name), np); icd->clk =v4l2_clk_register (&soc_camera_clk_ops, clk_name, icd);if (IS_ERR (icd->clk)) {
@@ -1591,6 +1592,7 @@ static int soc_of_bind(struct soc_camera_host *ici, eallocpdev:devm_kfree (ici->v4l2_dev.dev, info);dev_err (ici->v4l2_dev.dev,"group probe failed: %d\n" , ret); +of_node_put (np);return ret; }
@@ -1607,7 +1609,7 @@ static void scan_of_host(struct soc_camera_host *ici)if (!epn)break ; - rem =of_graph_get_remote_port_parent (epn); + rem =of_graph_get_remote_endpoint (epn);if (!rem) {dev_notice (dev,"no remote for %pOF\n" , epn);continue ;
Signature · 1 line
2.11.0
Re: [PATCH 2/9] v4l2-async: Use endpoint node, not device node, for fwnode match
Hi Sakari,
Thanks for your work.
Quoted 9 lines · Sakari Ailus
V4L2 async framework can use both device's fwnode and endpoints's fwnode for matching the async sub-device with the sub-device. In order to proceed moving towards endpoint matching assign the endpoint to the async sub-device.
As most async sub-device drivers (and the related hardware) only supports a single endpoint, use the first endpoint found. This works for all current drivers --- we only ever supported a single async sub-device per device to begin with.
Unfortunately this breaks for rcar-vin and adv7604 on Koelsch :-(
In DT we have the node:
i2chdmi: i2c-13 {
hdmi-in@4c {
compatible = "adi,adv7612";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
adv7612_in: endpoint {
remote-endpoint = <&hdmi_con_in>;
};
};
port@2 {
reg = <2>;
adv7612_out: endpoint {
remote-endpoint = <&vin0ep2>;
};
};
};
};
};- The rcar-vin in rvin_parallel_init() parses the DT using the v4l2_async_notifier_parse_fwnode_endpoints_by_port() helper and registers '/i2c-13/hdmi-in@4c/ports/port@2/endpoint' with the async framework.
- The adv7604 register itself with async using
'/i2c-13/hdmi-in@4c/ports/port@0/endpoint'.
The result is that matching breaks and the two devices never find each other. I'm not sure how to solve this :-( Maybe the subdevices could register itself multiple times with the async framework, once for each port described?
That would open up for the same subdev to be bound multiple times, possibly to different consumers. I think that is a direction that would be useful but I fear there might be some work involved in allowing that from a subdev point of view.
Quoted 411 lines
For async devices that have no endpoints, continue to use the fwnode related to the device. This includes e.g. lens devices.
Depends-on: ("pxa-camera: Match with device node, not the port node")
Signed-off-by Sakari Ailus <[email protected]>--- drivers/media/platform/am437x/am437x-vpfe.c | 2 +- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 20 +++++++++++++++----- drivers/media/platform/exynos4-is/media-dev.c | 14 ++++++++++---- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 10 +++++----- drivers/media/platform/rcar_drif.c | 2 +- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 13 ++++++++++--- drivers/media/v4l2-core/v4l2-async.c | 9 +++++++-- drivers/media/v4l2-core/v4l2-fwnode.c | 2 +- drivers/staging/media/soc_camera/soc_camera.c | 14 ++++++++------ 16 files changed, 65 insertions(+), 35 deletions(-)drivers/media/platform/am437x/am437x-vpfe.c +1
-1@@ -2495,7 +2495,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe)if (flags &V4L2_MBUS_VSYNC_ACTIVE_HIGH ) sdinfo->vpfe_param.vdpol =1 ; - rem =of_graph_get_remote_port_parent (endpoint); + rem =of_graph_get_remote_endpoint (endpoint);if (!rem) {dev_err (dev,"Remote device at %pOF not found\n" , endpoint);drivers/media/platform/atmel/atmel-isc.c +1
-1@@ -2042,7 +2042,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)if (!epn)return 0 ; - rem =of_graph_get_remote_port_parent (epn); + rem =of_graph_get_remote_endpoint (epn);if (!rem) {dev_notice (dev,"Remote device at %pOF not found\n" , epn);drivers/media/platform/atmel/atmel-isi.c +1
-1@@ -1110,7 +1110,7 @@ static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)if (!ep)return -EINVAL ; - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (!remote)return -EINVAL ;drivers/media/platform/cadence/cdns-csi2rx.c +1
-1@@ -395,7 +395,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)return -EINVAL ; } - csi2rx->asd.match.fwnode =fwnode_graph_get_remote_port_parent (fwh); + csi2rx->asd.match.fwnode =fwnode_graph_get_remote_endpoint (fwh); csi2rx->asd.match_type =V4L2_ASYNC_MATCH_FWNODE ;of_node_put (ep);drivers/media/platform/davinci/vpif_capture.c +15
-5@@ -1542,7 +1542,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)for (i =0 ; i <VPIF_CAPTURE_NUM_CHANNELS ; i++) {struct v4l2_fwnode_endpoint bus_cfg = { .bus_type =0 }; -struct device_node *rem; +struct device_node *rem, *rem_ep;unsigned int flags;int err;@@ -1551,13 +1551,22 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (!endpoint)break ; - rem =of_graph_get_remote_port_parent (endpoint); -if (!rem) { -dev_dbg (&pdev->dev,"Remote device at %pOF not found\n" , + rem_ep =of_graph_get_remote_endpoint (endpoint); +if (!rem_ep) { +dev_dbg (&pdev->dev,"Remote for endpoint %pOF not found\n" , endpoint); goto done; } + rem =of_graph_get_port_parent (rem_ep); +if (!rem) { +dev_dbg (&pdev->dev,"Remote endpoint at %pOF not found\n" , + rem_ep); +of_node_put (rem_ep); + goto done; + } +of_node_put (rem_ep); + sdinfo = &pdata->subdev_info[i]; chan = &pdata->chan_config[i]; chan->inputs = devm_kcalloc(&pdev->dev,@@ -1597,12 +1606,13 @@ vpif_capture_get_pdata(struct platform_device *pdev) sdinfo->name = rem->full_name; pdata->asd[i] =v4l2_async_notifier_add_fwnode_subdev ( - &vpif_obj.notifier,of_fwnode_handle (rem), + &vpif_obj.notifier,of_fwnode_handle (rem_ep),sizeof (struct v4l2_async_subdev ));if (IS_ERR (pdata->asd[i])) {of_node_put (rem); goto err_cleanup; } + } done:drivers/media/platform/exynos4-is/media-dev.c +10
-4@@ -411,7 +411,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->mux_id = (endpoint.base.port -1 ) &0x1 ; - rem =of_graph_get_remote_port_parent (ep); + rem =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (rem ==NULL ) { v4l2_info(&fmd->v4l2_dev, "Remote device at %pOF not found\n",@@ -1372,11 +1372,17 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,int i;/* Find platform data for this sensor subdev */ -for (i =0 ; i <ARRAY_SIZE (fmd->sensor); i++) -if (fmd->sensor[i].asd.match.fwnode == -of_fwnode_handle (subdev->dev->of_node)) +for (i =0 ; i <ARRAY_SIZE (fmd->sensor); i++) { +struct fwnode_handle *fwnode = +fwnode_graph_get_remote_port_parent (fmd->sensor[i].asd. + match.fwnode); + +if (fwnode ==of_fwnode_handle (subdev->dev->of_node)) si = &fmd->sensor[i]; +fwnode_handle_put (fwnode); + } +if (si ==NULL )return -EINVAL ;drivers/media/platform/pxa_camera.c +1
-1@@ -2350,7 +2350,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, pcdev->platform_flags |=PXA_CAMERA_PCLK_EN ; asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; - remote =of_graph_get_remote_port_parent (np); + remote =of_graph_get_remote_endpoint (np);if (remote) asd->match.fwnode =of_fwnode_handle (remote);else drivers/media/platform/qcom/camss/camss.c +5
-5@@ -466,7 +466,7 @@ static int camss_of_parse_ports(struct camss *camss) {struct device *dev = camss->dev;struct device_node *node =NULL ; -struct device_node *remote =NULL ; +struct fwnode_handle *remote =NULL ;int ret, num_subdevs =0 ;for_each_endpoint_of_node (dev->of_node, node) {@@ -476,7 +476,8 @@ static int camss_of_parse_ports(struct camss *camss)if (!of_device_is_available (node))continue ; - remote =of_graph_get_remote_port_parent (node); + remote =fwnode_graph_get_remote_endpoint ( +of_fwnode_handle (node));if (!remote) {dev_err (dev,"Cannot get remote parent\n" ); ret = -EINVAL ;@@ -484,11 +485,10 @@ static int camss_of_parse_ports(struct camss *camss) } asd =v4l2_async_notifier_add_fwnode_subdev ( - &camss->notifier,of_fwnode_handle (remote), -sizeof (*csd)); + &camss->notifier, remote,sizeof (*csd));if (IS_ERR (asd)) { ret =PTR_ERR (asd); -of_node_put (remote); +fwnode_handle_put (remote); goto err_cleanup; }drivers/media/platform/rcar_drif.c +1
-1@@ -1222,7 +1222,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)if (!ep)return 0 ; - fwnode =fwnode_graph_get_remote_port_parent (ep); + fwnode =fwnode_graph_get_remote_endpoint (ep);if (!fwnode) {dev_warn (sdr->dev,"bad remote port parent\n" );fwnode_handle_put (ep);drivers/media/platform/renesas-ceu.c +1
-1@@ -1581,7 +1581,7 @@ static int ceu_parse_dt(struct ceu_device *ceudev) ceu_sd = &ceudev->subdevs[i];INIT_LIST_HEAD (&ceu_sd->asd.list); - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep); ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; ceu_sd->asd.match_type =V4L2_ASYNC_MATCH_FWNODE ; ceu_sd->asd.match.fwnode =of_fwnode_handle (remote);drivers/media/platform/stm32/stm32-dcmi.c +1
-1@@ -1592,7 +1592,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)if (!ep)return -EINVAL ; - remote =of_graph_get_remote_port_parent (ep); + remote =of_graph_get_remote_endpoint (ep);of_node_put (ep);if (!remote)return -EINVAL ;drivers/media/platform/ti-vpe/cal.c +1
-1@@ -1693,7 +1693,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) goto cleanup_exit; } - sensor_node =of_graph_get_remote_port_parent (ep_node); + sensor_node =of_graph_get_remote_endpoint (ep_node);if (!sensor_node) {ctx_dbg (3 , ctx,"can't get remote parent\n" ); goto cleanup_exit;drivers/media/platform/xilinx/xilinx-vipp.c +10
-3@@ -14,6 +14,7 @@#include <linux/of.h> #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/slab.h> #include <media/v4l2-async.h> @@ -81,6 +82,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,dev_dbg (xdev->dev,"creating links for entity %s\n" , local->name);while (1 ) { +struct fwnode_handle *fwnode; +/* Get the next endpoint and parse its link. */ ep =fwnode_graph_get_next_endpoint (entity->asd.match.fwnode, ep);@@ -116,11 +119,13 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,continue ; } + fwnode =fwnode_graph_get_port_parent (link.remote_node); +fwnode_handle_put (fwnode); +/* Skip DMA engines, they will be processed separately. */ -if (link.remote_node ==of_fwnode_handle (xdev->dev->of_node)) { +if (fwnode ==dev_fwnode (xdev->dev)) {dev_dbg (xdev->dev,"skipping DMA port %p:%u\n" , link.local_node, link.local_port); -v4l2_fwnode_put_link (&link);continue ; }@@ -374,9 +379,11 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, }fwnode_handle_put (ep); + fwnode =fwnode_graph_get_port_parent (remote); +fwnode_handle_put (fwnode);/* Skip entities that we have already processed. */ -if (remote ==of_fwnode_handle (xdev->dev->of_node) || +if (fwnode ==dev_fwnode (xdev->dev) ||xvip_graph_find_entity (xdev, remote)) {fwnode_handle_put (remote);continue ;drivers/media/v4l2-core/v4l2-async.c +7
-2@@ -670,8 +670,13 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)* (struct v4l2_subdev.dev), and async sub-device does not * exist independently of the device at any point of time. */ -if (!sd->fwnode && sd->dev) - sd->fwnode =dev_fwnode (sd->dev); +if (!sd->fwnode && sd->dev) { + sd->fwnode =fwnode_graph_get_next_endpoint ( +dev_fwnode (sd->dev),NULL ); +fwnode_handle_put (sd->fwnode); +if (!sd->fwnode) + sd->fwnode =dev_fwnode (sd->dev); + }mutex_lock (&list_lock);drivers/media/v4l2-core/v4l2-fwnode.c +1
-1@@ -617,7 +617,7 @@ v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; asd->match.fwnode = -fwnode_graph_get_remote_port_parent (endpoint); +fwnode_graph_get_remote_endpoint (endpoint);if (!asd->match.fwnode) {dev_dbg (dev,"no remote endpoint found\n" ); ret = -ENOTCONN ;drivers/staging/media/soc_camera/soc_camera.c +8
-6@@ -1518,6 +1518,7 @@ static int soc_of_bind(struct soc_camera_host *ici,struct soc_camera_async_client *sasc;struct soc_of_info *info;struct i2c_client *client; +struct device_node *np;char clk_name[V4L2_CLK_NAME_SIZE ];int ret;@@ -1552,23 +1553,23 @@ static int soc_of_bind(struct soc_camera_host *ici,v4l2_async_notifier_init (&sasc->notifier); ret =v4l2_async_notifier_add_subdev (&sasc->notifier, info->subdev); -if (ret) { -of_node_put (remote); +if (ret) goto eaddasd; - } sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; + np =of_graph_get_port_parent (remote); +of_node_put (remote); - client =of_find_i2c_device_by_node (remote); + client =of_find_i2c_device_by_node (np);if (client)v4l2_clk_name_i2c (clk_name,sizeof (clk_name), client->adapter->nr, client->addr);else -v4l2_clk_name_of (clk_name,sizeof (clk_name), remote); +v4l2_clk_name_of (clk_name,sizeof (clk_name), np); icd->clk =v4l2_clk_register (&soc_camera_clk_ops, clk_name, icd);if (IS_ERR (icd->clk)) {@@ -1591,6 +1592,7 @@ static int soc_of_bind(struct soc_camera_host *ici, eallocpdev:devm_kfree (ici->v4l2_dev.dev, info);dev_err (ici->v4l2_dev.dev,"group probe failed: %d\n" , ret); +of_node_put (np);return ret; }@@ -1607,7 +1609,7 @@ static void scan_of_host(struct soc_camera_host *ici)if (!epn)break ; - rem =of_graph_get_remote_port_parent (epn); + rem =of_graph_get_remote_endpoint (epn);if (!rem) {dev_notice (dev,"no remote for %pOF\n" , epn);continue ;Signature · 1 line
2.11.0
Signature · 2 lines
Regards, Niklas Söderlund
Sakari Ailus
maintainerPATCH 3/9 v4l2-async: Get fwnode reference when putting it to the notifier's list
In reply to Sakari AilusThe v4l2_async_notifier_add_fwnode_subdev() did not take a reference of the added fwnode, relying on the caller to handle that instead, in essence putting the fwnode to be added if there was an error.
As the reference is eventually released during the notifier cleanup, this is not intuitive nor logical. Improve this by always getting a reference when the function succeeds, and the caller releasing the reference when it does not *itself* need it anymore.
Luckily, perhaps, there were just a handful of callers using the function.
--- drivers/media/platform/am437x/am437x-vpfe.c | 5 ++--- drivers/media/platform/davinci/vpif_capture.c | 16 ++++++++-------- drivers/media/platform/qcom/camss/camss.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 2 +- drivers/media/v4l2-core/v4l2-async.c | 3 ++- drivers/media/v4l2-core/v4l2-fwnode.c | 24 ++++++------------------ include/media/v4l2-async.h | 5 +++-- 7 files changed, 23 insertions(+), 34 deletions(-)
drivers/media/platform/am437x/am437x-vpfe.c +2 -3
@@ -2505,10 +2505,9 @@ vpfe_get_pdata(struct vpfe_device *vpfe) pdata->asd[i] =v4l2_async_notifier_add_fwnode_subdev ( &vpfe->notifier,of_fwnode_handle (rem),sizeof (struct v4l2_async_subdev )); -if (IS_ERR (pdata->asd[i])) { -of_node_put (rem); +of_node_put (rem); +if (IS_ERR (pdata->asd[i])) goto cleanup; - } }of_node_put (endpoint);
drivers/media/platform/davinci/vpif_capture.c +8 -8
@@ -1512,6 +1512,7 @@ static struct vpif_capture_config * vpif_capture_get_pdata(struct platform_device *pdev) {struct device_node *endpoint =NULL ; +struct device_node *rem =NULL , *rem_ep =NULL ;struct vpif_capture_config *pdata;struct vpif_subdev_info *sdinfo;struct vpif_capture_chan_config *chan;
@@ -1542,7 +1543,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)for (i =0 ; i <VPIF_CAPTURE_NUM_CHANNELS ; i++) {struct v4l2_fwnode_endpoint bus_cfg = { .bus_type =0 }; -struct device_node *rem, *rem_ep;unsigned int flags;int err;
@@ -1565,7 +1565,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)of_node_put (rem_ep); goto done; } -of_node_put (rem_ep); sdinfo = &pdata->subdev_info[i]; chan = &pdata->chan_config[i];
@@ -1573,10 +1572,8 @@ vpif_capture_get_pdata(struct platform_device *pdev)VPIF_CAPTURE_NUM_CHANNELS ,sizeof (*chan->inputs), GFP_KERNEL); -if (!chan->inputs) { -of_node_put (rem); +if (!chan->inputs) goto err_cleanup; - } chan->input_count++; chan->inputs[i].input.type =V4L2_INPUT_TYPE_CAMERA ;
@@ -1588,6 +1585,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)if (err) {dev_err (&pdev->dev,"Could not parse the endpoint\n" );of_node_put (rem); +of_node_put (rem_ep); goto done; }
@@ -1608,11 +1606,11 @@ vpif_capture_get_pdata(struct platform_device *pdev) pdata->asd[i] =v4l2_async_notifier_add_fwnode_subdev ( &vpif_obj.notifier,of_fwnode_handle (rem_ep),sizeof (struct v4l2_async_subdev )); -if (IS_ERR (pdata->asd[i])) { -of_node_put (rem); +if (IS_ERR (pdata->asd[i])) goto err_cleanup; - } +of_node_put (rem); +of_node_put (rem_ep); } done:
@@ -1624,6 +1622,8 @@ vpif_capture_get_pdata(struct platform_device *pdev)return pdata; err_cleanup: +of_node_put (rem); +of_node_put (rem_ep);of_node_put (endpoint);v4l2_async_notifier_cleanup (&vpif_obj.notifier);
drivers/media/platform/qcom/camss/camss.c +1 -1
@@ -486,9 +486,9 @@ static int camss_of_parse_ports(struct camss *camss) asd =v4l2_async_notifier_add_fwnode_subdev ( &camss->notifier, remote,sizeof (*csd)); +fwnode_handle_put (remote);if (IS_ERR (asd)) { ret =PTR_ERR (asd); -fwnode_handle_put (remote); goto err_cleanup; }
drivers/media/platform/xilinx/xilinx-vipp.c +1 -1
@@ -392,9 +392,9 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, asd =v4l2_async_notifier_add_fwnode_subdev ( &xdev->notifier, remote,sizeof (struct xvip_graph_entity )); +fwnode_handle_put (remote);if (IS_ERR (asd)) { ret =PTR_ERR (asd); -fwnode_handle_put (remote); goto err_notifier_cleanup; } }
drivers/media/v4l2-core/v4l2-async.c +2 -1
@@ -596,10 +596,11 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,return ERR_PTR (-ENOMEM ); asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; - asd->match.fwnode = fwnode; + asd->match.fwnode =fwnode_handle_get (fwnode); ret =v4l2_async_notifier_add_subdev (notifier, asd);if (ret) { +fwnode_handle_put (fwnode);kfree (asd);return ERR_PTR (ret); }
drivers/media/v4l2-core/v4l2-fwnode.c +6 -18
@@ -780,23 +780,17 @@ static int v4l2_fwnode_reference_parse(struct device *dev, asd =v4l2_async_notifier_add_fwnode_subdev (notifier, args.fwnode,sizeof (*asd)); +fwnode_handle_put (args.fwnode);if (IS_ERR (asd)) { - ret =PTR_ERR (asd);/* not an error if asd already exists */ -if (ret == -EEXIST ) { -fwnode_handle_put (args.fwnode); +if (PTR_ERR (asd) == -EEXIST )continue ; - } - goto error; +return PTR_ERR (asd); } }return 0 ; - -error: -fwnode_handle_put (args.fwnode); -return ret; }/*
@@ -1086,23 +1080,17 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, asd =v4l2_async_notifier_add_fwnode_subdev (notifier, fwnode,sizeof (*asd)); +fwnode_handle_put (fwnode);if (IS_ERR (asd)) { - ret =PTR_ERR (asd);/* not an error if asd already exists */ -if (ret == -EEXIST ) { -fwnode_handle_put (fwnode); +if (PTR_ERR (asd) == -EEXIST )continue ; - } - goto error; +return PTR_ERR (asd); } }return PTR_ERR (fwnode) == -ENOENT ?0 :PTR_ERR (fwnode); - -error: -fwnode_handle_put (fwnode); -return ret; } int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev,
include/media/v4l2-async.h +3 -2
@@ -175,8 +175,9 @@ int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,* the driver's async sub-device struct, i.e. both * begin at the same memory address. * -* Allocate a fwnode-matched asd of size asd_struct_size, and add it -* to the notifiers @asd_list. +* Allocate a fwnode-matched asd of size asd_struct_size, and add it to the +* notifiers @asd_list. The function also gets a reference of the fwnode which +* is released later at notifier cleanup time. */ struct v4l2_async_subdev * v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 4/9 v4l2-async: Add v4l2_async_notifier_add_fwnode_remote_subdev
In reply to Sakari Ailusv4l2_async_notifier_add_fwnode_remote_subdev is a convenience function for parsing information on V4L2 fwnode subdevs.
--- drivers/media/v4l2-core/v4l2-async.c | 23 +++++++++++++++++++++++ include/media/v4l2-async.h | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
drivers/media/v4l2-core/v4l2-async.c +23 -0
@@ -609,6 +609,29 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, }EXPORT_SYMBOL_GPL (v4l2_async_notifier_add_fwnode_subdev); +int +v4l2_async_notifier_add_fwnode_remote_subdev (struct v4l2_async_notifier *notif, +struct fwnode_handle *endpoint, +struct v4l2_async_subdev *asd) +{ +struct fwnode_handle *remote_ep; +int ret; + + remote_ep =fwnode_graph_get_remote_endpoint (endpoint); +if (!remote_ep) +return -ENOTCONN ; + + asd->match_type =V4L2_ASYNC_MATCH_FWNODE ; + asd->match.fwnode = remote_ep; + + ret =v4l2_async_notifier_add_subdev (notif, asd); +if (ret) +fwnode_handle_put (remote_ep); + +return ret; +} +EXPORT_SYMBOL_GPL (v4l2_async_notifier_add_fwnode_remote_subdev); +struct v4l2_async_subdev * v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier, int adapter_id, unsigned short address,
include/media/v4l2-async.h +25 -0
@@ -185,6 +185,31 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier, unsigned int asd_struct_size);/** +* v4l2_async_notifier_add_fwnode_remote_subdev - Allocate and add a fwnode +* remote async subdev to the +* notifier's master asd_list. +* +* @notif: pointer to &struct v4l2_async_notifier +* @endpoint: local endpoint the remote sub-device to be matched +* @asd: Async sub-device struct allocated by the caller. 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. +* +* Gets the remote endpoint of a given local endpoint, set it up for fwnode +* matching and add the async sub-device to the notifier's @asd_list. The +* function also gets a reference of the fwnode which is released later at +* notifier cleanup time. +* +* This is just like @v4l2_async_notifier_add_fwnode_subdev, but with the +* exception that the fwnode refers to a local endpoint, not the remote one, and +* the function relies on the caller to allocate the async sub-device struct. +*/ +int +v4l2_async_notifier_add_fwnode_remote_subdev (struct v4l2_async_notifier *notif, +struct fwnode_handle *endpoint, +struct v4l2_async_subdev *asd); + +/** * v4l2_async_notifier_add_i2c_subdev - Allocate and add an i2c async * subdev to the notifier's master asd_list. *
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 5/9 omap3isp: Rework OF endpoint parsing
In reply to Sakari AilusRework OF endpoint parsing for the omap3isp driver. This does add some lines of code. The benefits are still clear:
- the great complication related to callbacks in endpoint parsing is gone; instead endpoints are obtained port by port and
- endpoints may now have a default bus configuration which was not possible while using callbacks. This driver does not benefit from that feature, but as the omap3isp is one of the exemplary drivers, this works as an example for driver developers.
Depends-on: ("device property: Add fwnode_graph_get_endpoint_by_id")
--- drivers/media/platform/omap3isp/isp.c | 331 ++++++++++++++++++++-------------- 1 file changed, 197 insertions(+), 134 deletions(-)
drivers/media/platform/omap3isp/isp.c +197 -134
@@ -2015,136 +2015,6 @@ enum isp_of_phy { ISP_OF_PHY_CSIPHY2, }; -static int isp_fwnode_parse (struct device *dev, -struct v4l2_fwnode_endpoint *vep, -struct v4l2_async_subdev *asd) -{ -struct isp_async_subdev *isd = - container_of(asd, struct isp_async_subdev, asd); -struct isp_bus_cfg *buscfg = &isd->bus; -bool csi1 = false; -unsigned int i; - -dev_dbg (dev,"parsing endpoint %pOF, interface %u\n" , -to_of_node (vep->base.local_fwnode), vep->base.port); - -switch (vep->base.port) { -case ISP_OF_PHY_PARALLEL : - buscfg->interface =ISP_INTERFACE_PARALLEL ; - buscfg->bus.parallel.data_lane_shift = - vep->bus.parallel.data_shift; - buscfg->bus.parallel.clk_pol = - !!(vep->bus.parallel.flags - &V4L2_MBUS_PCLK_SAMPLE_FALLING ); - buscfg->bus.parallel.hs_pol = - !!(vep->bus.parallel.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW ); - buscfg->bus.parallel.vs_pol = - !!(vep->bus.parallel.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW ); - buscfg->bus.parallel.fld_pol = - !!(vep->bus.parallel.flags &V4L2_MBUS_FIELD_EVEN_LOW ); - buscfg->bus.parallel.data_pol = - !!(vep->bus.parallel.flags &V4L2_MBUS_DATA_ACTIVE_LOW ); - buscfg->bus.parallel.bt656 = vep->bus_type ==V4L2_MBUS_BT656 ; -break ; - -case ISP_OF_PHY_CSIPHY1 : -case ISP_OF_PHY_CSIPHY2 : -switch (vep->bus_type) { -case V4L2_MBUS_CCP2 : -case V4L2_MBUS_CSI1 : -dev_dbg (dev,"CSI-1/CCP-2 configuration\n" ); - csi1 = true; -break ; -case V4L2_MBUS_CSI2_DPHY : -dev_dbg (dev,"CSI-2 configuration\n" ); - csi1 = false; -break ; -default : -dev_err (dev,"unsupported bus type %u\n" , - vep->bus_type); -return -EINVAL ; - } - -switch (vep->base.port) { -case ISP_OF_PHY_CSIPHY1 : -if (csi1) - buscfg->interface =ISP_INTERFACE_CCP2B_PHY1 ; -else - buscfg->interface =ISP_INTERFACE_CSI2C_PHY1 ; -break ; -case ISP_OF_PHY_CSIPHY2 : -if (csi1) - buscfg->interface =ISP_INTERFACE_CCP2B_PHY2 ; -else - buscfg->interface =ISP_INTERFACE_CSI2A_PHY2 ; -break ; - } -if (csi1) { - buscfg->bus.ccp2.lanecfg.clk.pos = - vep->bus.mipi_csi1.clock_lane; - buscfg->bus.ccp2.lanecfg.clk.pol = - vep->bus.mipi_csi1.lane_polarity[0 ]; -dev_dbg (dev,"clock lane polarity %u, pos %u\n" , - buscfg->bus.ccp2.lanecfg.clk.pol, - buscfg->bus.ccp2.lanecfg.clk.pos); - - buscfg->bus.ccp2.lanecfg.data[0 ].pos = - vep->bus.mipi_csi1.data_lane; - buscfg->bus.ccp2.lanecfg.data[0 ].pol = - vep->bus.mipi_csi1.lane_polarity[1 ]; - -dev_dbg (dev,"data lane polarity %u, pos %u\n" , - buscfg->bus.ccp2.lanecfg.data[0 ].pol, - buscfg->bus.ccp2.lanecfg.data[0 ].pos); - - buscfg->bus.ccp2.strobe_clk_pol = - vep->bus.mipi_csi1.clock_inv; - buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; - buscfg->bus.ccp2.ccp2_mode = - vep->bus_type ==V4L2_MBUS_CCP2 ; - buscfg->bus.ccp2.vp_clk_pol =1 ; - - buscfg->bus.ccp2.crc =1 ; - }else { - buscfg->bus.csi2.lanecfg.clk.pos = - vep->bus.mipi_csi2.clock_lane; - buscfg->bus.csi2.lanecfg.clk.pol = - vep->bus.mipi_csi2.lane_polarities[0 ]; -dev_dbg (dev,"clock lane polarity %u, pos %u\n" , - buscfg->bus.csi2.lanecfg.clk.pol, - buscfg->bus.csi2.lanecfg.clk.pos); - - buscfg->bus.csi2.num_data_lanes = - vep->bus.mipi_csi2.num_data_lanes; - -for (i =0 ; i < buscfg->bus.csi2.num_data_lanes; i++) { - buscfg->bus.csi2.lanecfg.data[i].pos = - vep->bus.mipi_csi2.data_lanes[i]; - buscfg->bus.csi2.lanecfg.data[i].pol = - vep->bus.mipi_csi2.lane_polarities[i +1 ]; -dev_dbg (dev, -"data lane %u polarity %u, pos %u\n" , i, - buscfg->bus.csi2.lanecfg.data[i].pol, - buscfg->bus.csi2.lanecfg.data[i].pos); - } -/* -* FIXME: now we assume the CRC is always there. -* Implement a way to obtain this information from the -* sensor. Frame descriptors, perhaps? -*/ - buscfg->bus.csi2.crc =1 ; - } -break ; - -default : -dev_warn (dev,"%pOF: invalid interface %u\n" , -to_of_node (vep->base.local_fwnode), vep->base.port); -return -EINVAL ; - } - -return 0 ; -} -static int isp_subdev_notifier_complete (struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device,
@@ -2174,6 +2044,201 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)return media_device_register (&isp->media_dev); } +static void isp_parse_of_parallel_endpoint (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct isp_bus_cfg *buscfg) +{ + buscfg->interface =ISP_INTERFACE_PARALLEL ; + buscfg->bus.parallel.data_lane_shift = vep->bus.parallel.data_shift; + buscfg->bus.parallel.clk_pol = + !!(vep->bus.parallel.flags &V4L2_MBUS_PCLK_SAMPLE_FALLING ); + buscfg->bus.parallel.hs_pol = + !!(vep->bus.parallel.flags &V4L2_MBUS_VSYNC_ACTIVE_LOW ); + buscfg->bus.parallel.vs_pol = + !!(vep->bus.parallel.flags &V4L2_MBUS_HSYNC_ACTIVE_LOW ); + buscfg->bus.parallel.fld_pol = + !!(vep->bus.parallel.flags &V4L2_MBUS_FIELD_EVEN_LOW ); + buscfg->bus.parallel.data_pol = + !!(vep->bus.parallel.flags &V4L2_MBUS_DATA_ACTIVE_LOW ); + buscfg->bus.parallel.bt656 = vep->bus_type ==V4L2_MBUS_BT656 ; +} + +static void isp_parse_of_csi2_endpoint (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct isp_bus_cfg *buscfg) +{ +unsigned int i; + + buscfg->bus.csi2.lanecfg.clk.pos = vep->bus.mipi_csi2.clock_lane; + buscfg->bus.csi2.lanecfg.clk.pol = + vep->bus.mipi_csi2.lane_polarities[0 ]; +dev_dbg (dev,"clock lane polarity %u, pos %u\n" , + buscfg->bus.csi2.lanecfg.clk.pol, + buscfg->bus.csi2.lanecfg.clk.pos); + + buscfg->bus.csi2.num_data_lanes = vep->bus.mipi_csi2.num_data_lanes; + +for (i =0 ; i < buscfg->bus.csi2.num_data_lanes; i++) { + buscfg->bus.csi2.lanecfg.data[i].pos = + vep->bus.mipi_csi2.data_lanes[i]; + buscfg->bus.csi2.lanecfg.data[i].pol = + vep->bus.mipi_csi2.lane_polarities[i +1 ]; +dev_dbg (dev, +"data lane %u polarity %u, pos %u\n" , i, + buscfg->bus.csi2.lanecfg.data[i].pol, + buscfg->bus.csi2.lanecfg.data[i].pos); + } +/* +* FIXME: now we assume the CRC is always there. Implement a way to +* obtain this information from the sensor. Frame descriptors, perhaps? +*/ + buscfg->bus.csi2.crc =1 ; +} + +static void isp_parse_of_csi1_endpoint (struct device *dev, +struct v4l2_fwnode_endpoint *vep, +struct isp_bus_cfg *buscfg) +{ + buscfg->bus.ccp2.lanecfg.clk.pos = vep->bus.mipi_csi1.clock_lane; + buscfg->bus.ccp2.lanecfg.clk.pol = vep->bus.mipi_csi1.lane_polarity[0 ]; +dev_dbg (dev,"clock lane polarity %u, pos %u\n" , + buscfg->bus.ccp2.lanecfg.clk.pol, + buscfg->bus.ccp2.lanecfg.clk.pos); + + buscfg->bus.ccp2.lanecfg.data[0 ].pos = vep->bus.mipi_csi1.data_lane; + buscfg->bus.ccp2.lanecfg.data[0 ].pol = + vep->bus.mipi_csi1.lane_polarity[1 ]; + +dev_dbg (dev,"data lane polarity %u, pos %u\n" , + buscfg->bus.ccp2.lanecfg.data[0 ].pol, + buscfg->bus.ccp2.lanecfg.data[0 ].pos); + + buscfg->bus.ccp2.strobe_clk_pol = vep->bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; + buscfg->bus.ccp2.ccp2_mode = vep->bus_type ==V4L2_MBUS_CCP2 ; + buscfg->bus.ccp2.vp_clk_pol =1 ; + + buscfg->bus.ccp2.crc =1 ; +} + +static int isp_alloc_isd (struct isp_async_subdev **isd, +struct isp_bus_cfg **buscfg) +{ +struct isp_async_subdev *__isd; + + __isd =kzalloc (sizeof (*isd),GFP_KERNEL ); +if (!__isd) +return -ENOMEM ; + + *isd = __isd; + *buscfg = &__isd->bus; + +return 0 ; +} + +static struct { +u32 phy; +u32 csi2_if; +u32 csi1_if; +} isp_bus_interfaces[2 ] = { + {ISP_OF_PHY_CSIPHY1 , +ISP_INTERFACE_CSI2C_PHY1 ,ISP_INTERFACE_CCP2B_PHY1 }, + {ISP_OF_PHY_CSIPHY2 , +ISP_INTERFACE_CSI2A_PHY2 ,ISP_INTERFACE_CCP2B_PHY2 }, +}; + +static int isp_parse_of_endpoints (struct isp_device *isp) +{ +struct fwnode_handle *ep; +struct isp_async_subdev *isd =NULL ; +struct isp_bus_cfg *buscfg; +unsigned int i; + + ep =fwnode_graph_get_endpoint_by_id ( +dev_fwnode (isp->dev),ISP_OF_PHY_PARALLEL ,0 , +FWNODE_GRAPH_ENDPOINT_NEXT ); + +if (ep) { +struct v4l2_fwnode_endpoint vep = { + .bus_type =V4L2_MBUS_PARALLEL + }; +int ret; + +dev_dbg (isp->dev,"parsing parallel interface\n" ); + + ret =v4l2_fwnode_endpoint_parse (ep, &vep); + +if (!ret) { + ret =isp_alloc_isd (&isd, &buscfg); +if (ret) +return ret; + } + +if (!ret) { +isp_parse_of_parallel_endpoint (isp->dev, &vep, buscfg); + ret =v4l2_async_notifier_add_fwnode_remote_subdev ( + &isp->notifier, ep, &isd->asd); + } + +fwnode_handle_put (ep); +if (ret) +kfree (isd); + } + +for (i =0 ; i <ARRAY_SIZE (isp_bus_interfaces); i++) { +struct v4l2_fwnode_endpoint vep = { + .bus_type =V4L2_MBUS_CSI2_DPHY + }; +int ret; + + ep =fwnode_graph_get_endpoint_by_id ( +dev_fwnode (isp->dev), isp_bus_interfaces[i].phy,0 , +FWNODE_GRAPH_ENDPOINT_NEXT ); + +if (!ep) +continue ; + +dev_dbg (isp->dev,"parsing serial interface %u, node %pOF\n" , i, +to_of_node (ep)); + + ret =isp_alloc_isd (&isd, &buscfg); +if (ret) +return ret; + + ret =v4l2_fwnode_endpoint_parse (ep, &vep); +if (!ret) { + buscfg->interface = isp_bus_interfaces[i].csi2_if; +isp_parse_of_csi2_endpoint (isp->dev, &vep, buscfg); + }else if (ret == -ENXIO ) { + vep = (struct v4l2_fwnode_endpoint ) + { .bus_type =V4L2_MBUS_CSI1 }; + ret =v4l2_fwnode_endpoint_parse (ep, &vep); + +if (ret == -ENXIO ) { + vep = (struct v4l2_fwnode_endpoint ) + { .bus_type =V4L2_MBUS_CCP2 }; + ret =v4l2_fwnode_endpoint_parse (ep, &vep); + } +if (!ret) { + buscfg->interface = + isp_bus_interfaces[i].csi1_if; +isp_parse_of_csi1_endpoint (isp->dev, &vep, + buscfg); + } + } + +if (!ret) + ret =v4l2_async_notifier_add_fwnode_remote_subdev ( + &isp->notifier, ep, &isd->asd); + +fwnode_handle_put (ep); +if (ret) +kfree (isd); + } + +return 0 ; +} +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = { .complete = isp_subdev_notifier_complete, };
@@ -2222,14 +2287,12 @@ static int isp_probe(struct platform_device *pdev)mutex_init (&isp->isp_mutex);spin_lock_init (&isp->stat_lock);v4l2_async_notifier_init (&isp->notifier); + isp->dev = &pdev->dev; - ret =v4l2_async_notifier_parse_fwnode_endpoints ( - &pdev->dev, &isp->notifier,sizeof (struct isp_async_subdev ), - isp_fwnode_parse); + ret =isp_parse_of_endpoints (isp);if (ret <0 ) goto error; - isp->dev = &pdev->dev; isp->ref_count =0 ; ret =dma_coerce_mask_and_coherent (isp->dev,DMA_BIT_MASK (32 ));
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 6/9 v4l2-async: Safely clean up an uninitialised notifier
In reply to Sakari AilusMake the V4L2 async framework a bit more robust by allowing to clean up an uninitialised notifier. Otherwise the result would be a (close to) NULL pointer dereference.
--- drivers/media/v4l2-core/v4l2-async.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/v4l2-core/v4l2-async.c +1 -1
@@ -537,7 +537,7 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) {struct v4l2_async_subdev *asd, *tmp; -if (!notifier) +if (!notifier || !notifier->asd_list.next)return ;list_for_each_entry_safe (asd, tmp, ¬ifier->asd_list, asd_list) {
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 7/9 ipu3-cio2: Clean up notifier's subdev list if parsing endpoints fails
In reply to Sakari AilusThe notifier must be cleaned up whenever parsing endpoints fails. Do that to avoid a memory leak in that case.
--- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/media/pci/intel/ipu3/ipu3-cio2.c +6 -2
@@ -1504,7 +1504,7 @@ static int cio2_notifier_init(struct cio2_device *cio2)sizeof (struct sensor_async_subdev ), cio2_fwnode_parse);if (ret <0 ) -return ret; + goto out;if (list_empty (&cio2->notifier.asd_list))return -ENODEV ;/* no endpoint */
@@ -1514,9 +1514,13 @@ static int cio2_notifier_init(struct cio2_device *cio2)if (ret) {dev_err (&cio2->pci_dev->dev,"failed to register async notifier : %d\n" , ret); -v4l2_async_notifier_cleanup (&cio2->notifier); + goto out; } +out: +if (ret) +v4l2_async_notifier_cleanup (&cio2->notifier); +return ret; }
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 8/9 ipu3-cio2: Proceed with notifier init even if there are no subdevs
In reply to Sakari AilusThe notifier may be registered even if there are no subdevs. Do that to simplify the code.
--- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/media/pci/intel/ipu3/ipu3-cio2.c +5 -5
@@ -1506,9 +1506,10 @@ static int cio2_notifier_init(struct cio2_device *cio2)if (ret <0 ) goto out; -if (list_empty (&cio2->notifier.asd_list)) -return -ENODEV ;/* no endpoint */ - +/* +* Proceed even without sensors connected to allow the device to +* suspend. +*/ cio2->notifier.ops = &cio2_async_ops; ret =v4l2_async_notifier_register (&cio2->v4l2_dev, &cio2->notifier);if (ret) {
@@ -1815,8 +1816,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,/* Register notifier for subdevices we care */ r =cio2_notifier_init (cio2); -/* Proceed without sensors connected to allow the device to suspend. */ -if (r && r != -ENODEV ) +if (r) goto fail_cio2_queue_exit; r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq,
Signature · 1 line
2.11.0
Sakari Ailus
maintainerPATCH 9/9 ipu3-cio2: Parse information from firmware without using callbacks
In reply to Sakari AilusInstead of using the convenience function v4l2_async_notifier_parse_fwnode_endpoints(), parse the endpoints and set up the async sub-devices without using callbacks. While this adds a little bit of code, it makes parsing the endpoints quite a bit more simple and gives more control to the driver over the process. The parsing assumes D-PHY instead of letting the V4L2 fwnode framework guess it.
--- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 92 +++++++++++++++++--------------- 1 file changed, 49 insertions(+), 43 deletions(-)
drivers/media/pci/intel/ipu3/ipu3-cio2.c +49 -43
@@ -1475,36 +1475,51 @@ static const struct v4l2_async_notifier_operations cio2_async_ops = { .complete = cio2_notifier_complete, }; -static int cio2_fwnode_parse (struct device *dev, -struct v4l2_fwnode_endpoint *vep, -struct v4l2_async_subdev *asd) +static int cio2_parse_firmware (struct cio2_device *cio2) { -struct sensor_async_subdev *s_asd = - container_of(asd, struct sensor_async_subdev, asd); +unsigned int i; +int ret; -if (vep->bus_type !=V4L2_MBUS_CSI2_DPHY ) { -dev_err (dev,"Only CSI2 bus type is currently supported\n" ); -return -EINVAL ; - } +for (i =0 ; i <CIO2_NUM_PORTS ; i++) { +struct v4l2_fwnode_endpoint vep = { + .bus_type =V4L2_MBUS_CSI2_DPHY + }; +struct sensor_async_subdev *s_asd =NULL ; +struct fwnode_handle *ep; - s_asd->csi2.port = vep->base.port; - s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes; + ep =fwnode_graph_get_endpoint_by_id ( +dev_fwnode (&cio2->pci_dev->dev), i,0 , +FWNODE_GRAPH_ENDPOINT_NEXT ); -return 0 ; -} +if (!ep) +continue ; -static int cio2_notifier_init (struct cio2_device *cio2) -{ -int ret; + ret =v4l2_fwnode_endpoint_parse (ep, &vep); +if (ret) + goto err_parse; -v4l2_async_notifier_init (&cio2->notifier); + s_asd =kzalloc (sizeof (*s_asd),GFP_KERNEL ); +if (!s_asd) { + ret = -ENOMEM ; + goto err_parse; + } - ret =v4l2_async_notifier_parse_fwnode_endpoints ( - &cio2->pci_dev->dev, &cio2->notifier, -sizeof (struct sensor_async_subdev ), - cio2_fwnode_parse); -if (ret <0 ) - goto out; + s_asd->csi2.port = vep.base.port; + s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes; + + ret =v4l2_async_notifier_add_fwnode_remote_subdev ( + &cio2->notifier, ep, &s_asd->asd); +fwnode_handle_put (ep); +if (ret) + goto err_parse; + +continue ; + +err_parse: +fwnode_handle_put (ep); +kfree (s_asd); +return ret; + }/* * Proceed even without sensors connected to allow the device to
@@ -1512,25 +1527,13 @@ static int cio2_notifier_init(struct cio2_device *cio2)*/ cio2->notifier.ops = &cio2_async_ops; ret =v4l2_async_notifier_register (&cio2->v4l2_dev, &cio2->notifier); -if (ret) { +if (ret)dev_err (&cio2->pci_dev->dev,"failed to register async notifier : %d\n" , ret); - goto out; - } - -out: -if (ret) -v4l2_async_notifier_cleanup (&cio2->notifier);return ret; } -static void cio2_notifier_exit (struct cio2_device *cio2) -{ -v4l2_async_notifier_unregister (&cio2->notifier); -v4l2_async_notifier_cleanup (&cio2->notifier); -} -/**************** Queue initialization ****************/ static const struct media_entity_operations cio2_media_ops = { .link_validate = v4l2_subdev_link_validate,
@@ -1814,16 +1817,18 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,if (r) goto fail_v4l2_device_unregister; +v4l2_async_notifier_init (&cio2->notifier); +/* Register notifier for subdevices we care */ - r =cio2_notifier_init (cio2); + r =cio2_parse_firmware (cio2);if (r) - goto fail_cio2_queue_exit; + goto fail_clean_notifier; r =devm_request_irq (&pci_dev->dev, pci_dev->irq, cio2_irq,IRQF_SHARED ,CIO2_NAME , cio2);if (r) {dev_err (&pci_dev->dev,"failed to request IRQ (%d)\n" , r); - goto fail; + goto fail_clean_notifier; }pm_runtime_put_noidle (&pci_dev->dev);
@@ -1831,9 +1836,9 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,return 0 ; -fail: -cio2_notifier_exit (cio2); -fail_cio2_queue_exit: +fail_clean_notifier: +v4l2_async_notifier_unregister (&cio2->notifier); +v4l2_async_notifier_cleanup (&cio2->notifier);cio2_queues_exit (cio2); fail_v4l2_device_unregister:v4l2_device_unregister (&cio2->v4l2_dev);
@@ -1852,7 +1857,8 @@ static void cio2_pci_remove(struct pci_dev *pci_dev)struct cio2_device *cio2 =pci_get_drvdata (pci_dev);media_device_unregister (&cio2->media_dev); -cio2_notifier_exit (cio2); +v4l2_async_notifier_unregister (&cio2->notifier); +v4l2_async_notifier_cleanup (&cio2->notifier);cio2_queues_exit (cio2);cio2_fbpt_exit_dummy (cio2);v4l2_device_unregister (&cio2->v4l2_dev);
Signature · 1 line
2.11.0
Quoted 5 lines · Sakari Ailus
- Add another patch to change fwnode refcounting for
v4l2_async_notifier_add_fwnode_subdev- Add a patch to fix OF node refcounting and use / put order for davinci-vpif
If you wondered why does adding two patches to an 8-patch set makes a 9-patch set, the explanation is that another patch got dropped: "[RFC 3/8]
v4l2-fwnode: Use v4l2_async_notifier_add_fwnode_remote_subdev". The parse_endpoint() may use information from async sub-device filled by the same function.
Signature · 1 line
Sakari Ailus
Hi Sakari,
Quoted 27 lines · Sakari Ailus
Hi folks,
This patchset reworks V4L2 fwnode endpoint parsing. It enables the use of endpoint configuration defaults that is available sensors and other drivers that only use a single endpoint. Well, the functionality was available already but no driver used it likely because of two reasons:
lack of any examples in a non-trivial problem area as well as lack of a needed functionality to obtain through non-iterative means in the fwnode graph API. Also the fwnode framework did not provide the most convenient APIs to perform this for drivers.Conversion from the iterative API is done for the omap3isp and ipu3-cio2 drivers. A downside here is that this adds code: what used to be done in the framework in a one-size-fits-all fashion is now the responsibility of the driver. The benefits (default settings and simplicity of the implementation from driver's point of view) are not really achievable without some of that.
Also baked in the set is matching devices with endpoints by endpoint node rather than the device's node. This allows finding out more information than just the device bound (i.e. the port --- or endpoint --- through which it was bound). Compatibility support is provided for existing drivers by setting the fwnode to be matched based on the available endpoints. Drivers that use the async non-notifier API and have multiple ports will likely need special care and this is right now missing from the set, hence this is RFC for now.
Quoted 4 lines
The set depends on a few other patches. They all can be found here:
<URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=fwnode-linear>
Compared to the above tree I see one missing patch:
"device property: Add fwnode_graph_get_endpoint_by_id"
Is this intentional?
Thanks
j
Quoted 56 lines
since RFC v1:
- Add another patch to change fwnode refcounting for
v4l2_async_notifier_add_fwnode_subdev- Add a patch to fix OF node refcounting and use / put order for davinci-vpif
- Don't take endpoint reference in
v4l2_async_register_subdev; that's not intended- Fix kerneldoc documentation for
v4l2_async_notifier_add_fwnode_remote_subdev- Fix endpoint refcounting in the patch changing fwnode parsing for the omap3isp driver
- Fixed a compiler error in
rcar_drif.c--- thanks, Niklas!Sakari Ailus (9):
davinci-vpif: Don't dereference endpoint after putting it, fix
refcounting
v4l2-async: Use endpoint node, not device node, for fwnode match
v4l2-async: Get fwnode reference when putting it to the notifier's
list
v4l2-async: Addv4l2_async_notifier_add_fwnode_remote_subdev
omap3isp: Rework OF endpoint parsing
v4l2-async: Safely clean up an uninitialised notifier
ipu3-cio2: Clean up notifier's subdev list if parsing endpoints fails
ipu3-cio2: Proceed with notifier init even if there are no subdevs
ipu3-cio2: Parse information from firmware without using callbacksdrivers/media/pci/intel/ipu3/ipu3-cio2.c | 96 ++++---- drivers/media/platform/am437x/am437x-vpfe.c | 7 +- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 37 +-- drivers/media/platform/exynos4-is/media-dev.c | 14 +- drivers/media/platform/omap3isp/isp.c | 331 +++++++++++++++----------- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 10 +- drivers/media/platform/rcar_drif.c | 2 +- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 15 +- drivers/media/v4l2-core/v4l2-async.c | 37 ++- drivers/media/v4l2-core/v4l2-fwnode.c | 26 +- drivers/staging/media/soc_camera/soc_camera.c | 14 +- include/media/v4l2-async.h | 30 ++- 19 files changed, 386 insertions(+), 247 deletions(-)--
2.11.0
Sakari Ailus
maintainerQuoted 32 lines · Jacopo Mondi
Hi Sakari,
Quoted 29 lines · Sakari Ailus
Hi folks,
This patchset reworks V4L2 fwnode endpoint parsing. It enables the use of endpoint configuration defaults that is available sensors and other drivers that only use a single endpoint. Well, the functionality was available already but no driver used it likely because of two reasons:
lack of any examples in a non-trivial problem area as well as lack of a needed functionality to obtain through non-iterative means in the fwnode graph API. Also the fwnode framework did not provide the most convenient APIs to perform this for drivers.Conversion from the iterative API is done for the omap3isp and ipu3-cio2 drivers. A downside here is that this adds code: what used to be done in the framework in a one-size-fits-all fashion is now the responsibility of the driver. The benefits (default settings and simplicity of the implementation from driver's point of view) are not really achievable without some of that.
Also baked in the set is matching devices with endpoints by endpoint node rather than the device's node. This allows finding out more information than just the device bound (i.e. the port --- or endpoint --- through which it was bound). Compatibility support is provided for existing drivers by setting the fwnode to be matched based on the available endpoints. Drivers that use the async non-notifier API and have multiple ports will likely need special care and this is right now missing from the set, hence this is RFC for now.
The set depends on a few other patches. They all can be found here:
Quoted 7 lines
Quoted 2 lines
<URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=fwnode-linear>
Compared to the above tree I see one missing patch:
"device property: Addfwnode_graph_get_endpoint_by_id"Is this intentional?
Yes. That patch will be merged through the ACPI tree (I hope). I guess it's time to ping. :-)
Quoted 60 lines
Thanks
jQuoted 56 lines
since RFC v1:
- Add another patch to change fwnode refcounting for
v4l2_async_notifier_add_fwnode_subdev- Add a patch to fix OF node refcounting and use / put order for davinci-vpif
- Don't take endpoint reference in
v4l2_async_register_subdev; that's not intended- Fix kerneldoc documentation for
v4l2_async_notifier_add_fwnode_remote_subdev- Fix endpoint refcounting in the patch changing fwnode parsing for the omap3isp driver
- Fixed a compiler error in
rcar_drif.c--- thanks, Niklas!Sakari Ailus (9):
davinci-vpif: Don't dereference endpoint after putting it, fix
refcounting
v4l2-async: Use endpoint node, not device node, for fwnode match
v4l2-async: Get fwnode reference when putting it to the notifier's
list
v4l2-async: Addv4l2_async_notifier_add_fwnode_remote_subdev
omap3isp: Rework OF endpoint parsing
v4l2-async: Safely clean up an uninitialised notifier
ipu3-cio2: Clean up notifier's subdev list if parsing endpoints fails
ipu3-cio2: Proceed with notifier init even if there are no subdevs
ipu3-cio2: Parse information from firmware without using callbacksdrivers/media/pci/intel/ipu3/ipu3-cio2.c | 96 ++++---- drivers/media/platform/am437x/am437x-vpfe.c | 7 +- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/platform/atmel/atmel-isi.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 37 +-- drivers/media/platform/exynos4-is/media-dev.c | 14 +- drivers/media/platform/omap3isp/isp.c | 331 +++++++++++++++----------- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 10 +- drivers/media/platform/rcar_drif.c | 2 +- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/xilinx/xilinx-vipp.c | 15 +- drivers/media/v4l2-core/v4l2-async.c | 37 ++- drivers/media/v4l2-core/v4l2-fwnode.c | 26 +- drivers/staging/media/soc_camera/soc_camera.c | 14 +- include/media/v4l2-async.h | 30 ++- 19 files changed, 386 insertions(+), 247 deletions(-)--
2.11.0
Signature · 2 lines
Sakari Ailus [email protected]