Commit 621b08ea authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Mauro Carvalho Chehab

media: staging/imx: remove static media link arrays

Remove the static list of media links that were formed at probe time.
These links can instead be created after all registered async subdevices
have been bound in imx_media_probe_complete().

The media links between subdevices that exist in the device tree, can
be created post-async completion by using v4l2_fwnode_parse_link() for
each endpoint node of that subdevice. Note this approach assumes
device-tree ports are equivalent to media pads (pad index equals
port id), and that device-tree endpoints are equivalent to media
links between pads.

Because links are no longer parsed by imx_media_of_parse(), its sole
function is now only to add subdevices that it encounters by walking
the OF graph to the async list, so the function has been renamed
imx_media_add_of_subdevs().

Similarly, the media links between the IPU-internal subdevice pads (the
CSI source pads, and all pads between the vdic, ic-prp, ic-prpenc, and
ic-prpvf subdevices), can be created post-async completion by looping
through the subdevice's media pads and using the const internal_subdev
table.

Because links are no longer parsed by imx_media_add_internal_subdevs(),
this function no longer needs an array of CSI subdevs to form links
from.

In summary, the following functions, which were used to form a list
of media links at probe time, are removed:

imx_media_add_pad_link()
add_internal_links()
of_add_pad_link()

replaced by these functions, called at probe time, which only populate
the async subdev list:

imx_media_add_of_subdevs()
imx_media_add_internal_subdevs()

and these functions, called at async completion, which create the
media links:

imx_media_create_of_links()
imx_media_create_csi_of_links()
imx_media_create_internal_links()
Signed-off-by: default avatarSteve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent bf3cfaa7
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -127,50 +128,6 @@ imx_media_add_async_subdev(struct imx_media_dev *imxmd, ...@@ -127,50 +128,6 @@ imx_media_add_async_subdev(struct imx_media_dev *imxmd,
return imxsd; return imxsd;
} }
/*
* Adds an imx-media link to a subdev pad's link list. This is called
* during driver load when forming the links between subdevs.
*
* @pad: the local pad
* @remote_node: the device node of the remote subdev
* @remote_devname: the device name of the remote subdev
* @local_pad: local pad index
* @remote_pad: remote pad index
*/
int imx_media_add_pad_link(struct imx_media_dev *imxmd,
struct imx_media_pad *pad,
struct device_node *remote_node,
const char *remote_devname,
int local_pad, int remote_pad)
{
struct imx_media_link *link;
int link_idx, ret = 0;
mutex_lock(&imxmd->mutex);
link_idx = pad->num_links;
if (link_idx >= IMX_MEDIA_MAX_LINKS) {
dev_err(imxmd->md.dev, "%s: too many links!\n", __func__);
ret = -ENOSPC;
goto out;
}
link = &pad->link[link_idx];
link->remote_sd_node = remote_node;
if (remote_devname)
strncpy(link->remote_devname, remote_devname,
sizeof(link->remote_devname));
link->local_pad = local_pad;
link->remote_pad = remote_pad;
pad->num_links++;
out:
mutex_unlock(&imxmd->mutex);
return ret;
}
/* /*
* get IPU from this CSI and add it to the list of IPUs * get IPU from this CSI and add it to the list of IPUs
* the media driver will control. * the media driver will control.
...@@ -240,76 +197,38 @@ static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, ...@@ -240,76 +197,38 @@ static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
} }
/* /*
* Create a single source->sink media link given a subdev and a single * create the media links from all pads and their links.
* link from one of its source pads. Called after all subdevs have
* registered.
*/
static int imx_media_create_link(struct imx_media_dev *imxmd,
struct imx_media_subdev *src,
struct imx_media_link *link)
{
struct imx_media_subdev *sink;
u16 source_pad, sink_pad;
int ret;
sink = imx_media_find_async_subdev(imxmd, link->remote_sd_node,
link->remote_devname);
if (!sink) {
v4l2_warn(&imxmd->v4l2_dev, "%s: no sink for %s:%d\n",
__func__, src->sd->name, link->local_pad);
return 0;
}
source_pad = link->local_pad;
sink_pad = link->remote_pad;
v4l2_info(&imxmd->v4l2_dev, "%s: %s:%d -> %s:%d\n", __func__,
src->sd->name, source_pad, sink->sd->name, sink_pad);
ret = media_create_pad_link(&src->sd->entity, source_pad,
&sink->sd->entity, sink_pad, 0);
if (ret)
v4l2_err(&imxmd->v4l2_dev,
"create_pad_link failed: %d\n", ret);
return ret;
}
/*
* create the media links from all imx-media pads and their links.
* Called after all subdevs have registered. * Called after all subdevs have registered.
*/ */
static int imx_media_create_links(struct imx_media_dev *imxmd) static int imx_media_create_links(struct imx_media_dev *imxmd)
{ {
struct imx_media_subdev *imxsd; struct imx_media_subdev *imxsd;
struct imx_media_link *link; struct v4l2_subdev *sd;
struct imx_media_pad *pad; int i, ret;
int num_pads, i, j, k;
int ret = 0;
for (i = 0; i < imxmd->num_subdevs; i++) { for (i = 0; i < imxmd->num_subdevs; i++) {
imxsd = &imxmd->subdev[i]; imxsd = &imxmd->subdev[i];
num_pads = imxsd->num_sink_pads + imxsd->num_src_pads; sd = imxsd->sd;
for (j = 0; j < num_pads; j++) {
pad = &imxsd->pad[j];
/* only create the source->sink links */ if (((sd->grp_id & IMX_MEDIA_GRP_ID_CSI) || imxsd->pdev)) {
if (!(pad->pad.flags & MEDIA_PAD_FL_SOURCE)) /* this is an internal subdev or a CSI */
continue; ret = imx_media_create_internal_links(imxmd, imxsd);
for (k = 0; k < pad->num_links; k++) {
link = &pad->link[k];
ret = imx_media_create_link(imxmd, imxsd, link);
if (ret) if (ret)
goto out; return ret;
} /*
* the CSIs straddle between the external and the IPU
* internal entities, so create the external links
* to the CSI sink pads.
*/
if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI)
imx_media_create_csi_of_links(imxmd, imxsd);
} else {
/* this is an external fwnode subdev */
imx_media_create_of_links(imxmd, imxsd);
} }
} }
out: return 0;
return ret;
} }
/* /*
...@@ -550,7 +469,6 @@ static int imx_media_probe(struct platform_device *pdev) ...@@ -550,7 +469,6 @@ static int imx_media_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct imx_media_subdev *csi[4] = {0};
struct imx_media_dev *imxmd; struct imx_media_dev *imxmd;
int ret; int ret;
...@@ -581,14 +499,14 @@ static int imx_media_probe(struct platform_device *pdev) ...@@ -581,14 +499,14 @@ static int imx_media_probe(struct platform_device *pdev)
dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd); dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
ret = imx_media_of_parse(imxmd, &csi, node); ret = imx_media_add_of_subdevs(imxmd, node);
if (ret) { if (ret) {
v4l2_err(&imxmd->v4l2_dev, v4l2_err(&imxmd->v4l2_dev,
"imx_media_of_parse failed with %d\n", ret); "add_of_subdevs failed with %d\n", ret);
goto unreg_dev; goto unreg_dev;
} }
ret = imx_media_add_internal_subdevs(imxmd, csi); ret = imx_media_add_internal_subdevs(imxmd);
if (ret) { if (ret) {
v4l2_err(&imxmd->v4l2_dev, v4l2_err(&imxmd->v4l2_dev,
"add_internal_subdevs failed with %d\n", ret); "add_internal_subdevs failed with %d\n", ret);
......
...@@ -60,14 +60,19 @@ static const struct internal_subdev_id { ...@@ -60,14 +60,19 @@ static const struct internal_subdev_id {
}, },
}; };
struct internal_subdev;
struct internal_link { struct internal_link {
const struct internal_subdev_id *remote_id; const struct internal_subdev *remote;
int local_pad;
int remote_pad; int remote_pad;
}; };
/* max links per internal-sd pad */
#define MAX_INTERNAL_LINKS 8
struct internal_pad { struct internal_pad {
bool devnode; /* does this pad link to a device node */ struct internal_link link[MAX_INTERNAL_LINKS];
struct internal_link link[IMX_MEDIA_MAX_LINKS];
}; };
static const struct internal_subdev { static const struct internal_subdev {
...@@ -75,7 +80,7 @@ static const struct internal_subdev { ...@@ -75,7 +80,7 @@ static const struct internal_subdev {
struct internal_pad pad[IMX_MEDIA_MAX_PADS]; struct internal_pad pad[IMX_MEDIA_MAX_PADS];
int num_sink_pads; int num_sink_pads;
int num_src_pads; int num_src_pads;
} internal_subdev[num_isd] = { } int_subdev[num_isd] = {
[isd_csi0] = { [isd_csi0] = {
.id = &isd_id[isd_csi0], .id = &isd_id[isd_csi0],
.num_sink_pads = CSI_NUM_SINK_PADS, .num_sink_pads = CSI_NUM_SINK_PADS,
...@@ -83,17 +88,16 @@ static const struct internal_subdev { ...@@ -83,17 +88,16 @@ static const struct internal_subdev {
.pad[CSI_SRC_PAD_DIRECT] = { .pad[CSI_SRC_PAD_DIRECT] = {
.link = { .link = {
{ {
.remote_id = &isd_id[isd_ic_prp], .local_pad = CSI_SRC_PAD_DIRECT,
.remote = &int_subdev[isd_ic_prp],
.remote_pad = PRP_SINK_PAD, .remote_pad = PRP_SINK_PAD,
}, { }, {
.remote_id = &isd_id[isd_vdic], .local_pad = CSI_SRC_PAD_DIRECT,
.remote = &int_subdev[isd_vdic],
.remote_pad = VDIC_SINK_PAD_DIRECT, .remote_pad = VDIC_SINK_PAD_DIRECT,
}, },
}, },
}, },
.pad[CSI_SRC_PAD_IDMAC] = {
.devnode = true,
},
}, },
[isd_csi1] = { [isd_csi1] = {
...@@ -103,30 +107,27 @@ static const struct internal_subdev { ...@@ -103,30 +107,27 @@ static const struct internal_subdev {
.pad[CSI_SRC_PAD_DIRECT] = { .pad[CSI_SRC_PAD_DIRECT] = {
.link = { .link = {
{ {
.remote_id = &isd_id[isd_ic_prp], .local_pad = CSI_SRC_PAD_DIRECT,
.remote = &int_subdev[isd_ic_prp],
.remote_pad = PRP_SINK_PAD, .remote_pad = PRP_SINK_PAD,
}, { }, {
.remote_id = &isd_id[isd_vdic], .local_pad = CSI_SRC_PAD_DIRECT,
.remote = &int_subdev[isd_vdic],
.remote_pad = VDIC_SINK_PAD_DIRECT, .remote_pad = VDIC_SINK_PAD_DIRECT,
}, },
}, },
}, },
.pad[CSI_SRC_PAD_IDMAC] = {
.devnode = true,
},
}, },
[isd_vdic] = { [isd_vdic] = {
.id = &isd_id[isd_vdic], .id = &isd_id[isd_vdic],
.num_sink_pads = VDIC_NUM_SINK_PADS, .num_sink_pads = VDIC_NUM_SINK_PADS,
.num_src_pads = VDIC_NUM_SRC_PADS, .num_src_pads = VDIC_NUM_SRC_PADS,
.pad[VDIC_SINK_PAD_IDMAC] = {
.devnode = true,
},
.pad[VDIC_SRC_PAD_DIRECT] = { .pad[VDIC_SRC_PAD_DIRECT] = {
.link = { .link = {
{ {
.remote_id = &isd_id[isd_ic_prp], .local_pad = VDIC_SRC_PAD_DIRECT,
.remote = &int_subdev[isd_ic_prp],
.remote_pad = PRP_SINK_PAD, .remote_pad = PRP_SINK_PAD,
}, },
}, },
...@@ -140,7 +141,8 @@ static const struct internal_subdev { ...@@ -140,7 +141,8 @@ static const struct internal_subdev {
.pad[PRP_SRC_PAD_PRPENC] = { .pad[PRP_SRC_PAD_PRPENC] = {
.link = { .link = {
{ {
.remote_id = &isd_id[isd_ic_prpenc], .local_pad = PRP_SRC_PAD_PRPENC,
.remote = &int_subdev[isd_ic_prpenc],
.remote_pad = 0, .remote_pad = 0,
}, },
}, },
...@@ -148,7 +150,8 @@ static const struct internal_subdev { ...@@ -148,7 +150,8 @@ static const struct internal_subdev {
.pad[PRP_SRC_PAD_PRPVF] = { .pad[PRP_SRC_PAD_PRPVF] = {
.link = { .link = {
{ {
.remote_id = &isd_id[isd_ic_prpvf], .local_pad = PRP_SRC_PAD_PRPVF,
.remote = &int_subdev[isd_ic_prpvf],
.remote_pad = 0, .remote_pad = 0,
}, },
}, },
...@@ -159,68 +162,114 @@ static const struct internal_subdev { ...@@ -159,68 +162,114 @@ static const struct internal_subdev {
.id = &isd_id[isd_ic_prpenc], .id = &isd_id[isd_ic_prpenc],
.num_sink_pads = PRPENCVF_NUM_SINK_PADS, .num_sink_pads = PRPENCVF_NUM_SINK_PADS,
.num_src_pads = PRPENCVF_NUM_SRC_PADS, .num_src_pads = PRPENCVF_NUM_SRC_PADS,
.pad[PRPENCVF_SRC_PAD] = {
.devnode = true,
},
}, },
[isd_ic_prpvf] = { [isd_ic_prpvf] = {
.id = &isd_id[isd_ic_prpvf], .id = &isd_id[isd_ic_prpvf],
.num_sink_pads = PRPENCVF_NUM_SINK_PADS, .num_sink_pads = PRPENCVF_NUM_SINK_PADS,
.num_src_pads = PRPENCVF_NUM_SRC_PADS, .num_src_pads = PRPENCVF_NUM_SRC_PADS,
.pad[PRPENCVF_SRC_PAD] = {
.devnode = true,
},
}, },
}; };
/* form a device name given a group id and ipu id */ /* form a device name given an internal subdev and ipu id */
static inline void isd_id_to_devname(char *devname, int sz, static inline void isd_to_devname(char *devname, int sz,
const struct internal_subdev_id *id, const struct internal_subdev *isd,
int ipu_id) int ipu_id)
{ {
int pdev_id = ipu_id * num_isd + id->index; int pdev_id = ipu_id * num_isd + isd->id->index;
snprintf(devname, sz, "%s.%d", id->name, pdev_id); snprintf(devname, sz, "%s.%d", isd->id->name, pdev_id);
} }
/* adds the links from given internal subdev */ static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id)
static int add_internal_links(struct imx_media_dev *imxmd, {
const struct internal_subdev *isd, enum isd_enum i;
struct imx_media_subdev *imxsd,
int ipu_id) for (i = 0; i < num_isd; i++) {
const struct internal_subdev *isd = &int_subdev[i];
if (isd->id->grp_id == grp_id)
return isd;
}
return NULL;
}
static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd,
struct imx_media_subdev *src,
const struct internal_link *link)
{ {
int i, num_pads, ret; char sink_devname[32];
int ipu_id;
num_pads = isd->num_sink_pads + isd->num_src_pads; /*
* retrieve IPU id from subdev name, note: can't get this from
* struct imx_media_internal_sd_platformdata because if src is
* a CSI, it has different struct ipu_client_platformdata which
* does not contain IPU id.
*/
if (sscanf(src->sd->name, "ipu%d", &ipu_id) != 1)
return NULL;
for (i = 0; i < num_pads; i++) { isd_to_devname(sink_devname, sizeof(sink_devname),
const struct internal_pad *intpad = &isd->pad[i]; link->remote, ipu_id - 1);
struct imx_media_pad *pad = &imxsd->pad[i];
int j;
/* init the pad flags for this internal subdev */ return imx_media_find_async_subdev(imxmd, NULL, sink_devname);
pad->pad.flags = (i < isd->num_sink_pads) ? }
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
/* export devnode pad flag to the subdevs */
pad->devnode = intpad->devnode;
for (j = 0; ; j++) { static int create_ipu_internal_link(struct imx_media_dev *imxmd,
struct imx_media_subdev *src,
const struct internal_link *link)
{
struct imx_media_subdev *sink;
int ret;
sink = find_sink(imxmd, src, link);
if (!sink)
return -ENODEV;
v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n",
src->sd->name, link->local_pad,
sink->sd->name, link->remote_pad);
ret = media_create_pad_link(&src->sd->entity, link->local_pad,
&sink->sd->entity, link->remote_pad, 0);
if (ret)
v4l2_err(&imxmd->v4l2_dev,
"create_pad_link failed: %d\n", ret);
return ret;
}
int imx_media_create_internal_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *imxsd)
{
struct v4l2_subdev *sd = imxsd->sd;
const struct internal_subdev *intsd;
const struct internal_pad *intpad;
const struct internal_link *link; const struct internal_link *link;
char remote_devname[32]; struct media_pad *pad;
int i, j, ret;
intsd = find_intsd_by_grp_id(imxsd->sd->grp_id);
if (!intsd)
return -ENODEV;
/* create the source->sink links */
for (i = 0; i < sd->entity.num_pads; i++) {
intpad = &intsd->pad[i];
pad = &sd->entity.pads[i];
if (!(pad->flags & MEDIA_PAD_FL_SOURCE))
continue;
for (j = 0; ; j++) {
link = &intpad->link[j]; link = &intpad->link[j];
if (!link->remote_id) if (!link->remote)
break; break;
isd_id_to_devname(remote_devname, ret = create_ipu_internal_link(imxmd, imxsd, link);
sizeof(remote_devname),
link->remote_id, ipu_id);
ret = imx_media_add_pad_link(imxmd, pad,
NULL, remote_devname,
i, link->remote_pad);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -230,8 +279,7 @@ static int add_internal_links(struct imx_media_dev *imxmd, ...@@ -230,8 +279,7 @@ static int add_internal_links(struct imx_media_dev *imxmd,
} }
/* register an internal subdev as a platform device */ /* register an internal subdev as a platform device */
static struct imx_media_subdev * static int add_internal_subdev(struct imx_media_dev *imxmd,
add_internal_subdev(struct imx_media_dev *imxmd,
const struct internal_subdev *isd, const struct internal_subdev *isd,
int ipu_id) int ipu_id)
{ {
...@@ -258,73 +306,58 @@ add_internal_subdev(struct imx_media_dev *imxmd, ...@@ -258,73 +306,58 @@ add_internal_subdev(struct imx_media_dev *imxmd,
pdev = platform_device_register_full(&pdevinfo); pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) if (IS_ERR(pdev))
return ERR_CAST(pdev); return PTR_ERR(pdev);
imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev); imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev);
if (IS_ERR(imxsd)) if (IS_ERR(imxsd))
return imxsd; return PTR_ERR(imxsd);
imxsd->num_sink_pads = isd->num_sink_pads; imxsd->num_sink_pads = isd->num_sink_pads;
imxsd->num_src_pads = isd->num_src_pads; imxsd->num_src_pads = isd->num_src_pads;
return imxsd; return 0;
} }
/* adds the internal subdevs in one ipu */ /* adds the internal subdevs in one ipu */
static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
struct imx_media_subdev *csi0,
struct imx_media_subdev *csi1,
int ipu_id)
{ {
enum isd_enum i; enum isd_enum i;
int ret;
for (i = 0; i < num_isd; i++) { for (i = 0; i < num_isd; i++) {
const struct internal_subdev *isd = &internal_subdev[i]; const struct internal_subdev *isd = &int_subdev[i];
struct imx_media_subdev *imxsd; int ret;
/* /*
* the CSIs are represented in the device-tree, so those * the CSIs are represented in the device-tree, so those
* devices are added already, and are added to the async * devices are already added to the async subdev list by
* subdev list by of_parse_subdev(), so we are given those * of_parse_subdev().
* subdevs as csi0 and csi1.
*/ */
switch (isd->id->grp_id) { switch (isd->id->grp_id) {
case IMX_MEDIA_GRP_ID_CSI0: case IMX_MEDIA_GRP_ID_CSI0:
imxsd = csi0;
break;
case IMX_MEDIA_GRP_ID_CSI1: case IMX_MEDIA_GRP_ID_CSI1:
imxsd = csi1; ret = 0;
break; break;
default: default:
imxsd = add_internal_subdev(imxmd, isd, ipu_id); ret = add_internal_subdev(imxmd, isd, ipu_id);
break; break;
} }
if (IS_ERR(imxsd))
return PTR_ERR(imxsd);
/* add the links from this subdev */
if (imxsd) {
ret = add_internal_links(imxmd, isd, imxsd, ipu_id);
if (ret) if (ret)
return ret; return ret;
} }
}
return 0; return 0;
} }
int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd, int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd)
struct imx_media_subdev *csi[4])
{ {
int ret; int ret;
ret = add_ipu_internal_subdevs(imxmd, csi[0], csi[1], 0); ret = add_ipu_internal_subdevs(imxmd, 0);
if (ret) if (ret)
goto remove; goto remove;
ret = add_ipu_internal_subdevs(imxmd, csi[2], csi[3], 1); ret = add_ipu_internal_subdevs(imxmd, 1);
if (ret) if (ret)
goto remove; goto remove;
......
...@@ -20,20 +20,6 @@ ...@@ -20,20 +20,6 @@
#include <video/imx-ipu-v3.h> #include <video/imx-ipu-v3.h>
#include "imx-media.h" #include "imx-media.h"
static int of_add_pad_link(struct imx_media_dev *imxmd,
struct imx_media_pad *pad,
struct device_node *local_sd_node,
struct device_node *remote_sd_node,
int local_pad, int remote_pad)
{
dev_dbg(imxmd->md.dev, "%s: adding %s:%d -> %s:%d\n", __func__,
local_sd_node->name, local_pad,
remote_sd_node->name, remote_pad);
return imx_media_add_pad_link(imxmd, pad, remote_sd_node, NULL,
local_pad, remote_pad);
}
static int of_get_port_count(const struct device_node *np) static int of_get_port_count(const struct device_node *np)
{ {
struct device_node *ports, *child; struct device_node *ports, *child;
...@@ -53,12 +39,10 @@ static int of_get_port_count(const struct device_node *np) ...@@ -53,12 +39,10 @@ static int of_get_port_count(const struct device_node *np)
} }
/* /*
* find the remote device node and remote port id (remote pad #) * find the remote device node given local endpoint node
* given local endpoint node
*/ */
static void of_get_remote_pad(struct device_node *epnode, static void of_get_remote(struct device_node *epnode,
struct device_node **remote_node, struct device_node **remote_node)
int *remote_pad)
{ {
struct device_node *rp, *rpp; struct device_node *rp, *rpp;
struct device_node *remote; struct device_node *remote;
...@@ -69,12 +53,9 @@ static void of_get_remote_pad(struct device_node *epnode, ...@@ -69,12 +53,9 @@ static void of_get_remote_pad(struct device_node *epnode,
if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) { if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) {
/* the remote is one of the CSI ports */ /* the remote is one of the CSI ports */
remote = rp; remote = rp;
*remote_pad = 0;
of_node_put(rpp); of_node_put(rpp);
} else { } else {
remote = rpp; remote = rpp;
if (of_property_read_u32(rp, "reg", remote_pad))
*remote_pad = 0;
of_node_put(rp); of_node_put(rp);
} }
...@@ -88,7 +69,7 @@ static void of_get_remote_pad(struct device_node *epnode, ...@@ -88,7 +69,7 @@ static void of_get_remote_pad(struct device_node *epnode,
static int static int
of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
bool is_csi_port, struct imx_media_subdev **subdev) bool is_csi_port)
{ {
struct imx_media_subdev *imxsd; struct imx_media_subdev *imxsd;
int i, num_pads, ret; int i, num_pads, ret;
...@@ -96,7 +77,6 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ...@@ -96,7 +77,6 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
if (!of_device_is_available(sd_np)) { if (!of_device_is_available(sd_np)) {
dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__, dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__,
sd_np->name); sd_np->name);
*subdev = NULL;
/* unavailable is not an error */ /* unavailable is not an error */
return 0; return 0;
} }
...@@ -107,14 +87,12 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ...@@ -107,14 +87,12 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
if (ret) { if (ret) {
if (ret == -EEXIST) { if (ret == -EEXIST) {
/* already added, everything is fine */ /* already added, everything is fine */
*subdev = NULL;
return 0; return 0;
} }
/* other error, can't continue */ /* other error, can't continue */
return ret; return ret;
} }
*subdev = imxsd;
if (is_csi_port) { if (is_csi_port) {
/* /*
...@@ -160,14 +138,6 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ...@@ -160,14 +138,6 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
for (i = 0; i < num_pads; i++) { for (i = 0; i < num_pads; i++) {
struct device_node *epnode = NULL, *port, *remote_np; struct device_node *epnode = NULL, *port, *remote_np;
struct imx_media_subdev *remote_imxsd;
struct imx_media_pad *pad;
int remote_pad;
/* init this pad */
pad = &imxsd->pad[i];
pad->pad.flags = (i < imxsd->num_sink_pads) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
if (is_csi_port) if (is_csi_port)
port = (i < imxsd->num_sink_pads) ? sd_np : NULL; port = (i < imxsd->num_sink_pads) ? sd_np : NULL;
...@@ -177,19 +147,13 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ...@@ -177,19 +147,13 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
continue; continue;
for_each_child_of_node(port, epnode) { for_each_child_of_node(port, epnode) {
of_get_remote_pad(epnode, &remote_np, &remote_pad); of_get_remote(epnode, &remote_np);
if (!remote_np) if (!remote_np)
continue; continue;
ret = of_add_pad_link(imxmd, pad, sd_np, remote_np,
i, remote_pad);
if (ret)
break;
if (i < imxsd->num_sink_pads) { if (i < imxsd->num_sink_pads) {
/* follow sink endpoints upstream */ /* follow sink endpoints upstream */
ret = of_parse_subdev(imxmd, remote_np, ret = of_parse_subdev(imxmd, remote_np, false);
false, &remote_imxsd);
if (ret) if (ret)
break; break;
} }
...@@ -209,13 +173,10 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, ...@@ -209,13 +173,10 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
return ret; return ret;
} }
int imx_media_of_parse(struct imx_media_dev *imxmd, int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
struct imx_media_subdev *(*csi)[4],
struct device_node *np) struct device_node *np)
{ {
struct imx_media_subdev *lcsi;
struct device_node *csi_np; struct device_node *csi_np;
u32 ipu_id, csi_id;
int i, ret; int i, ret;
for (i = 0; ; i++) { for (i = 0; ; i++) {
...@@ -223,33 +184,125 @@ int imx_media_of_parse(struct imx_media_dev *imxmd, ...@@ -223,33 +184,125 @@ int imx_media_of_parse(struct imx_media_dev *imxmd,
if (!csi_np) if (!csi_np)
break; break;
ret = of_parse_subdev(imxmd, csi_np, true, &lcsi); ret = of_parse_subdev(imxmd, csi_np, true);
of_node_put(csi_np);
if (ret) if (ret)
goto err_put; return ret;
ret = of_property_read_u32(csi_np, "reg", &csi_id);
if (ret) {
dev_err(imxmd->md.dev,
"%s: csi port missing reg property!\n",
__func__);
goto err_put;
} }
ipu_id = of_alias_get_id(csi_np->parent, "ipu"); return 0;
of_node_put(csi_np); }
if (ipu_id > 1 || csi_id > 1) { /*
dev_err(imxmd->md.dev, * Create a single media link to/from imxsd using a fwnode link.
"%s: invalid ipu/csi id (%u/%u)\n", *
__func__, ipu_id, csi_id); * NOTE: this function assumes an OF port node is equivalent to
* a media pad (port id equal to media pad index), and that an
* OF endpoint node is equivalent to a media link.
*/
static int create_of_link(struct imx_media_dev *imxmd,
struct imx_media_subdev *imxsd,
struct v4l2_fwnode_link *link)
{
struct v4l2_subdev *sd = imxsd->sd;
struct imx_media_subdev *remote;
struct v4l2_subdev *src, *sink;
int src_pad, sink_pad;
if (link->local_port >= sd->entity.num_pads)
return -EINVAL; return -EINVAL;
remote = imx_media_find_async_subdev(imxmd,
to_of_node(link->remote_node),
NULL);
if (!remote)
return 0;
if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
src = remote->sd;
src_pad = link->remote_port;
sink = sd;
sink_pad = link->local_port;
} else {
src = sd;
src_pad = link->local_port;
sink = remote->sd;
sink_pad = link->remote_port;
} }
(*csi)[ipu_id * 2 + csi_id] = lcsi; /* make sure link doesn't already exist before creating */
if (media_entity_find_link(&src->entity.pads[src_pad],
&sink->entity.pads[sink_pad]))
return 0;
v4l2_info(sd->v4l2_dev, "%s:%d -> %s:%d\n",
src->name, src_pad, sink->name, sink_pad);
return media_create_pad_link(&src->entity, src_pad,
&sink->entity, sink_pad, 0);
}
/*
* Create media links to/from imxsd using its device-tree endpoints.
*/
int imx_media_create_of_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *imxsd)
{
struct v4l2_subdev *sd = imxsd->sd;
struct v4l2_fwnode_link link;
struct device_node *ep;
int ret;
for_each_endpoint_of_node(sd->dev->of_node, ep) {
ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
if (ret)
continue;
ret = create_of_link(imxmd, imxsd, &link);
v4l2_fwnode_put_link(&link);
if (ret)
return ret;
} }
return 0; return 0;
err_put: }
of_node_put(csi_np);
/*
* Create media links to the given CSI subdevice's sink pads,
* using its device-tree endpoints.
*/
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *csi)
{
struct device_node *csi_np = csi->sd->dev->of_node;
struct fwnode_handle *fwnode, *csi_ep;
struct v4l2_fwnode_link link;
struct device_node *ep;
int ret;
link.local_node = of_fwnode_handle(csi_np);
link.local_port = CSI_SINK_PAD;
for_each_child_of_node(csi_np, ep) {
csi_ep = of_fwnode_handle(ep);
fwnode = fwnode_graph_get_remote_endpoint(csi_ep);
if (!fwnode)
continue;
fwnode = fwnode_get_parent(fwnode);
fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
fwnode = fwnode_get_next_parent(fwnode);
if (is_of_node(fwnode) &&
of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
fwnode = fwnode_get_next_parent(fwnode);
link.remote_node = fwnode;
ret = create_of_link(imxmd, csi, &link);
fwnode_handle_put(link.remote_node);
if (ret)
return ret; return ret;
}
return 0;
} }
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
#define IMX_MEDIA_MAX_SUBDEVS 32 #define IMX_MEDIA_MAX_SUBDEVS 32
/* max pads per subdev */ /* max pads per subdev */
#define IMX_MEDIA_MAX_PADS 16 #define IMX_MEDIA_MAX_PADS 16
/* max links per pad */
#define IMX_MEDIA_MAX_LINKS 8
/* /*
* Pad definitions for the subdevs with multiple source or * Pad definitions for the subdevs with multiple source or
...@@ -119,19 +117,7 @@ static inline struct imx_media_buffer *to_imx_media_vb(struct vb2_buffer *vb) ...@@ -119,19 +117,7 @@ static inline struct imx_media_buffer *to_imx_media_vb(struct vb2_buffer *vb)
return container_of(vbuf, struct imx_media_buffer, vbuf); return container_of(vbuf, struct imx_media_buffer, vbuf);
} }
struct imx_media_link {
struct device_node *remote_sd_node;
char remote_devname[32];
int local_pad;
int remote_pad;
};
struct imx_media_pad { struct imx_media_pad {
struct media_pad pad;
struct imx_media_link link[IMX_MEDIA_MAX_LINKS];
bool devnode; /* does this pad link to a device node */
int num_links;
/* /*
* list of video devices that can be reached from this pad, * list of video devices that can be reached from this pad,
* list is only valid for source pads. * list is only valid for source pads.
...@@ -154,7 +140,7 @@ struct imx_media_subdev { ...@@ -154,7 +140,7 @@ struct imx_media_subdev {
int num_sink_pads; int num_sink_pads;
int num_src_pads; int num_src_pads;
/* the platform device if this is an internal subdev */ /* the platform device if this is an IPU-internal subdev */
struct platform_device *pdev; struct platform_device *pdev;
/* the devname is needed for async devname match */ /* the devname is needed for async devname match */
char devname[32]; char devname[32];
...@@ -225,17 +211,13 @@ struct imx_media_subdev * ...@@ -225,17 +211,13 @@ struct imx_media_subdev *
imx_media_add_async_subdev(struct imx_media_dev *imxmd, imx_media_add_async_subdev(struct imx_media_dev *imxmd,
struct device_node *np, struct device_node *np,
struct platform_device *pdev); struct platform_device *pdev);
int imx_media_add_pad_link(struct imx_media_dev *imxmd,
struct imx_media_pad *pad,
struct device_node *remote_node,
const char *remote_devname,
int local_pad, int remote_pad);
void imx_media_grp_id_to_sd_name(char *sd_name, int sz, void imx_media_grp_id_to_sd_name(char *sd_name, int sz,
u32 grp_id, int ipu_id); u32 grp_id, int ipu_id);
int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd, int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd);
struct imx_media_subdev *csi[4]); int imx_media_create_internal_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *imxsd);
void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd); void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd);
struct imx_media_subdev * struct imx_media_subdev *
...@@ -284,13 +266,12 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd); ...@@ -284,13 +266,12 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim); void imx_media_fim_free(struct imx_media_fim *fim);
/* imx-media-of.c */ /* imx-media-of.c */
struct imx_media_subdev * int imx_media_add_of_subdevs(struct imx_media_dev *dev,
imx_media_of_find_subdev(struct imx_media_dev *imxmd,
struct device_node *np,
const char *name);
int imx_media_of_parse(struct imx_media_dev *dev,
struct imx_media_subdev *(*csi)[4],
struct device_node *np); struct device_node *np);
int imx_media_create_of_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *imxsd);
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
struct imx_media_subdev *csi);
/* imx-media-capture.c */ /* imx-media-capture.c */
struct imx_media_video_dev * struct imx_media_video_dev *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment