From 621b08eabcddb7a4ed6076dc91324c607be7e6b4 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Thu, 14 Dec 2017 20:04:40 -0500 Subject: 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: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-internal-sd.c | 219 +++++++++++++--------- 1 file changed, 126 insertions(+), 93 deletions(-) (limited to 'drivers/staging/media/imx/imx-media-internal-sd.c') diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index cdfbf40dfcbe..3e60df5f12d6 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -60,14 +60,19 @@ static const struct internal_subdev_id { }, }; +struct internal_subdev; + struct internal_link { - const struct internal_subdev_id *remote_id; + const struct internal_subdev *remote; + int local_pad; int remote_pad; }; +/* max links per internal-sd pad */ +#define MAX_INTERNAL_LINKS 8 + struct internal_pad { - bool devnode; /* does this pad link to a device node */ - struct internal_link link[IMX_MEDIA_MAX_LINKS]; + struct internal_link link[MAX_INTERNAL_LINKS]; }; static const struct internal_subdev { @@ -75,7 +80,7 @@ static const struct internal_subdev { struct internal_pad pad[IMX_MEDIA_MAX_PADS]; int num_sink_pads; int num_src_pads; -} internal_subdev[num_isd] = { +} int_subdev[num_isd] = { [isd_csi0] = { .id = &isd_id[isd_csi0], .num_sink_pads = CSI_NUM_SINK_PADS, @@ -83,17 +88,16 @@ static const struct internal_subdev { .pad[CSI_SRC_PAD_DIRECT] = { .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_id = &isd_id[isd_vdic], + .local_pad = CSI_SRC_PAD_DIRECT, + .remote = &int_subdev[isd_vdic], .remote_pad = VDIC_SINK_PAD_DIRECT, }, }, }, - .pad[CSI_SRC_PAD_IDMAC] = { - .devnode = true, - }, }, [isd_csi1] = { @@ -103,30 +107,27 @@ static const struct internal_subdev { .pad[CSI_SRC_PAD_DIRECT] = { .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_id = &isd_id[isd_vdic], + .local_pad = CSI_SRC_PAD_DIRECT, + .remote = &int_subdev[isd_vdic], .remote_pad = VDIC_SINK_PAD_DIRECT, }, }, }, - .pad[CSI_SRC_PAD_IDMAC] = { - .devnode = true, - }, }, [isd_vdic] = { .id = &isd_id[isd_vdic], .num_sink_pads = VDIC_NUM_SINK_PADS, .num_src_pads = VDIC_NUM_SRC_PADS, - .pad[VDIC_SINK_PAD_IDMAC] = { - .devnode = true, - }, .pad[VDIC_SRC_PAD_DIRECT] = { .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, }, }, @@ -140,7 +141,8 @@ static const struct internal_subdev { .pad[PRP_SRC_PAD_PRPENC] = { .link = { { - .remote_id = &isd_id[isd_ic_prpenc], + .local_pad = PRP_SRC_PAD_PRPENC, + .remote = &int_subdev[isd_ic_prpenc], .remote_pad = 0, }, }, @@ -148,7 +150,8 @@ static const struct internal_subdev { .pad[PRP_SRC_PAD_PRPVF] = { .link = { { - .remote_id = &isd_id[isd_ic_prpvf], + .local_pad = PRP_SRC_PAD_PRPVF, + .remote = &int_subdev[isd_ic_prpvf], .remote_pad = 0, }, }, @@ -159,68 +162,114 @@ static const struct internal_subdev { .id = &isd_id[isd_ic_prpenc], .num_sink_pads = PRPENCVF_NUM_SINK_PADS, .num_src_pads = PRPENCVF_NUM_SRC_PADS, - .pad[PRPENCVF_SRC_PAD] = { - .devnode = true, - }, }, [isd_ic_prpvf] = { .id = &isd_id[isd_ic_prpvf], .num_sink_pads = PRPENCVF_NUM_SINK_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 */ -static inline void isd_id_to_devname(char *devname, int sz, - const struct internal_subdev_id *id, - int ipu_id) +/* form a device name given an internal subdev and ipu id */ +static inline void isd_to_devname(char *devname, int sz, + const struct internal_subdev *isd, + 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 int add_internal_links(struct imx_media_dev *imxmd, - const struct internal_subdev *isd, - struct imx_media_subdev *imxsd, - int ipu_id) +static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id) { - int i, num_pads, ret; + enum isd_enum i; + + for (i = 0; i < num_isd; i++) { + const struct internal_subdev *isd = &int_subdev[i]; - num_pads = isd->num_sink_pads + isd->num_src_pads; + if (isd->id->grp_id == grp_id) + return isd; + } - for (i = 0; i < num_pads; i++) { - const struct internal_pad *intpad = &isd->pad[i]; - struct imx_media_pad *pad = &imxsd->pad[i]; - int j; + return NULL; +} - /* init the pad flags for this internal subdev */ - 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; +static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd, + struct imx_media_subdev *src, + const struct internal_link *link) +{ + char sink_devname[32]; + int ipu_id; + + /* + * 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; + + isd_to_devname(sink_devname, sizeof(sink_devname), + link->remote, ipu_id - 1); + + return imx_media_find_async_subdev(imxmd, NULL, sink_devname); +} - for (j = 0; ; j++) { - const struct internal_link *link; - char remote_devname[32]; +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; + 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]; - if (!link->remote_id) + if (!link->remote) break; - isd_id_to_devname(remote_devname, - sizeof(remote_devname), - link->remote_id, ipu_id); - - ret = imx_media_add_pad_link(imxmd, pad, - NULL, remote_devname, - i, link->remote_pad); + ret = create_ipu_internal_link(imxmd, imxsd, link); if (ret) return ret; } @@ -230,10 +279,9 @@ static int add_internal_links(struct imx_media_dev *imxmd, } /* register an internal subdev as a platform device */ -static struct imx_media_subdev * -add_internal_subdev(struct imx_media_dev *imxmd, - const struct internal_subdev *isd, - int ipu_id) +static int add_internal_subdev(struct imx_media_dev *imxmd, + const struct internal_subdev *isd, + int ipu_id) { struct imx_media_internal_sd_platformdata pdata; struct platform_device_info pdevinfo = {0}; @@ -258,73 +306,58 @@ add_internal_subdev(struct imx_media_dev *imxmd, pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) - return ERR_CAST(pdev); + return PTR_ERR(pdev); imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev); if (IS_ERR(imxsd)) - return imxsd; + return PTR_ERR(imxsd); imxsd->num_sink_pads = isd->num_sink_pads; imxsd->num_src_pads = isd->num_src_pads; - return imxsd; + return 0; } /* adds the internal subdevs in one ipu */ -static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, - struct imx_media_subdev *csi0, - struct imx_media_subdev *csi1, - int ipu_id) +static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id) { enum isd_enum i; - int ret; for (i = 0; i < num_isd; i++) { - const struct internal_subdev *isd = &internal_subdev[i]; - struct imx_media_subdev *imxsd; + const struct internal_subdev *isd = &int_subdev[i]; + int ret; /* * the CSIs are represented in the device-tree, so those - * devices are added already, and are added to the async - * subdev list by of_parse_subdev(), so we are given those - * subdevs as csi0 and csi1. + * devices are already added to the async subdev list by + * of_parse_subdev(). */ switch (isd->id->grp_id) { case IMX_MEDIA_GRP_ID_CSI0: - imxsd = csi0; - break; case IMX_MEDIA_GRP_ID_CSI1: - imxsd = csi1; + ret = 0; break; default: - imxsd = add_internal_subdev(imxmd, isd, ipu_id); + ret = add_internal_subdev(imxmd, isd, ipu_id); 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) - return ret; - } + if (ret) + return ret; } return 0; } -int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd, - struct imx_media_subdev *csi[4]) +int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd) { int ret; - ret = add_ipu_internal_subdevs(imxmd, csi[0], csi[1], 0); + ret = add_ipu_internal_subdevs(imxmd, 0); if (ret) goto remove; - ret = add_ipu_internal_subdevs(imxmd, csi[2], csi[3], 1); + ret = add_ipu_internal_subdevs(imxmd, 1); if (ret) goto remove; -- cgit From f5abe1c5f9bd3e5a4dad5079f6cd51641f2bf2a3 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Thu, 14 Dec 2017 20:04:41 -0500 Subject: media: staging/imx: of: allow for recursing downstream Calling of_parse_subdev() recursively to a downstream path that has already been followed is ok, it just means that call will return immediately since the subdevice was already added to the async list. With that there is no need to determine whether a subdevice's port is a sink or source, so 'num_{sink|src}_pads' is no longer used and is removed. Signed-off-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-internal-sd.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/staging/media/imx/imx-media-internal-sd.c') diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index 3e60df5f12d6..53f23830df82 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -78,13 +78,9 @@ struct internal_pad { static const struct internal_subdev { const struct internal_subdev_id *id; struct internal_pad pad[IMX_MEDIA_MAX_PADS]; - int num_sink_pads; - int num_src_pads; } int_subdev[num_isd] = { [isd_csi0] = { .id = &isd_id[isd_csi0], - .num_sink_pads = CSI_NUM_SINK_PADS, - .num_src_pads = CSI_NUM_SRC_PADS, .pad[CSI_SRC_PAD_DIRECT] = { .link = { { @@ -102,8 +98,6 @@ static const struct internal_subdev { [isd_csi1] = { .id = &isd_id[isd_csi1], - .num_sink_pads = CSI_NUM_SINK_PADS, - .num_src_pads = CSI_NUM_SRC_PADS, .pad[CSI_SRC_PAD_DIRECT] = { .link = { { @@ -121,8 +115,6 @@ static const struct internal_subdev { [isd_vdic] = { .id = &isd_id[isd_vdic], - .num_sink_pads = VDIC_NUM_SINK_PADS, - .num_src_pads = VDIC_NUM_SRC_PADS, .pad[VDIC_SRC_PAD_DIRECT] = { .link = { { @@ -136,8 +128,6 @@ static const struct internal_subdev { [isd_ic_prp] = { .id = &isd_id[isd_ic_prp], - .num_sink_pads = PRP_NUM_SINK_PADS, - .num_src_pads = PRP_NUM_SRC_PADS, .pad[PRP_SRC_PAD_PRPENC] = { .link = { { @@ -160,14 +150,10 @@ static const struct internal_subdev { [isd_ic_prpenc] = { .id = &isd_id[isd_ic_prpenc], - .num_sink_pads = PRPENCVF_NUM_SINK_PADS, - .num_src_pads = PRPENCVF_NUM_SRC_PADS, }, [isd_ic_prpvf] = { .id = &isd_id[isd_ic_prpvf], - .num_sink_pads = PRPENCVF_NUM_SINK_PADS, - .num_src_pads = PRPENCVF_NUM_SRC_PADS, }, }; @@ -312,9 +298,6 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, if (IS_ERR(imxsd)) return PTR_ERR(imxsd); - imxsd->num_sink_pads = isd->num_sink_pads; - imxsd->num_src_pads = isd->num_src_pads; - return 0; } -- cgit From 9f6a0c59eba91c116f6cd7a487f4929faa07a7f8 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Thu, 14 Dec 2017 20:04:44 -0500 Subject: media: staging/imx: remove static subdev arrays For more complex OF graphs, there will be more async subdevices registered. Remove the static subdev[IMX_MEDIA_MAX_SUBDEVS] array, so that imx-media places no limits on the number of async subdevs that can be added and registered. There were two uses for 'struct imx_media_subdev'. First was to act as the async subdev list to be passed to v4l2_async_notifier_register(). Second was to aid in inheriting subdev controls to the capture devices, and this is done by creating a list of capture devices that can be reached from a subdev's source pad. So 'struct imx_media_subdev' also contained a static array of 'struct imx_media_pad' for placing the capture device lists at each pad. 'struct imx_media_subdev' has been completely removed. Instead, at async completion, allocate an array of 'struct imx_media_pad' and attach it to the subdev's host_priv pointer, in order to support subdev controls inheritance. Likewise, remove static async_ptrs[IMX_MEDIA_MAX_SUBDEVS] array. Instead, allocate a 'struct imx_media_async_subdev' when forming the async list, and add it to an asd_list list_head in imx_media_add_async_subdev(). At async completion, allocate the asd pointer list and pull the asd's off asd_list for v4l2_async_notifier_register(). Signed-off-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-internal-sd.c | 51 ++++++++++------------- 1 file changed, 23 insertions(+), 28 deletions(-) (limited to 'drivers/staging/media/imx/imx-media-internal-sd.c') diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index 53f23830df82..70833fe503b5 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -68,6 +68,8 @@ struct internal_link { int remote_pad; }; +/* max pads per internal-sd */ +#define MAX_INTERNAL_PADS 8 /* max links per internal-sd pad */ #define MAX_INTERNAL_LINKS 8 @@ -77,7 +79,7 @@ struct internal_pad { static const struct internal_subdev { const struct internal_subdev_id *id; - struct internal_pad pad[IMX_MEDIA_MAX_PADS]; + struct internal_pad pad[MAX_INTERNAL_PADS]; } int_subdev[num_isd] = { [isd_csi0] = { .id = &isd_id[isd_csi0], @@ -181,9 +183,9 @@ static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id) return NULL; } -static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd, - struct imx_media_subdev *src, - const struct internal_link *link) +static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd, + struct v4l2_subdev *src, + const struct internal_link *link) { char sink_devname[32]; int ipu_id; @@ -194,20 +196,20 @@ static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd, * 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) + if (sscanf(src->name, "ipu%d", &ipu_id) != 1) return NULL; isd_to_devname(sink_devname, sizeof(sink_devname), link->remote, ipu_id - 1); - return imx_media_find_async_subdev(imxmd, NULL, sink_devname); + return imx_media_find_subdev_by_devname(imxmd, sink_devname); } static int create_ipu_internal_link(struct imx_media_dev *imxmd, - struct imx_media_subdev *src, + struct v4l2_subdev *src, const struct internal_link *link) { - struct imx_media_subdev *sink; + struct v4l2_subdev *sink; int ret; sink = find_sink(imxmd, src, link); @@ -215,11 +217,11 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd, return -ENODEV; v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n", - src->sd->name, link->local_pad, - sink->sd->name, link->remote_pad); + src->name, link->local_pad, + sink->name, link->remote_pad); - ret = media_create_pad_link(&src->sd->entity, link->local_pad, - &sink->sd->entity, link->remote_pad, 0); + ret = media_create_pad_link(&src->entity, link->local_pad, + &sink->entity, link->remote_pad, 0); if (ret) v4l2_err(&imxmd->v4l2_dev, "create_pad_link failed: %d\n", ret); @@ -228,16 +230,15 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd, } int imx_media_create_internal_links(struct imx_media_dev *imxmd, - struct imx_media_subdev *imxsd) + struct v4l2_subdev *sd) { - struct v4l2_subdev *sd = imxsd->sd; const struct internal_subdev *intsd; const struct internal_pad *intpad; const struct internal_link *link; struct media_pad *pad; int i, j, ret; - intsd = find_intsd_by_grp_id(imxsd->sd->grp_id); + intsd = find_intsd_by_grp_id(sd->grp_id); if (!intsd) return -ENODEV; @@ -255,7 +256,7 @@ int imx_media_create_internal_links(struct imx_media_dev *imxmd, if (!link->remote) break; - ret = create_ipu_internal_link(imxmd, imxsd, link); + ret = create_ipu_internal_link(imxmd, sd, link); if (ret) return ret; } @@ -271,7 +272,6 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, { struct imx_media_internal_sd_platformdata pdata; struct platform_device_info pdevinfo = {0}; - struct imx_media_subdev *imxsd; struct platform_device *pdev; pdata.grp_id = isd->id->grp_id; @@ -294,11 +294,7 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, if (IS_ERR(pdev)) return PTR_ERR(pdev); - imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev); - if (IS_ERR(imxsd)) - return PTR_ERR(imxsd); - - return 0; + return imx_media_add_async_subdev(imxmd, NULL, pdev); } /* adds the internal subdevs in one ipu */ @@ -353,13 +349,12 @@ remove: void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd) { - struct imx_media_subdev *imxsd; - int i; + struct imx_media_async_subdev *imxasd; - for (i = 0; i < imxmd->subdev_notifier.num_subdevs; i++) { - imxsd = &imxmd->subdev[i]; - if (!imxsd->pdev) + list_for_each_entry(imxasd, &imxmd->asd_list, list) { + if (!imxasd->pdev) continue; - platform_device_unregister(imxsd->pdev); + + platform_device_unregister(imxasd->pdev); } } -- cgit