Commit 6d01b7ff authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Mauro Carvalho Chehab

media: staging/imx: Switch to sync registration for IPU subdevs

Because the IPU sub-devices VDIC and IC are not present in the
device-tree, platform devices were created for them instead. This
allowed these sub-devices to be added to the media device's async
notifier and registered asynchronously along with the other
sub-devices that do have a device-tree presence (CSI and devices
external to the IPU and SoC).

But that approach isn't really necessary. The IPU sub-devices don't
actually require a backing device (sd->dev is allowed to be NULL).
And that approach can't get around the fact that the IPU sub-devices
are not part of a device hierarchy, which makes it awkward to retrieve
the parent IPU of these devices.

By registering them synchronously, they can be registered from the CSI
async bound notifier, so the init function for them can be given the CSI
subdev, who's dev->parent is the IPU. That is a somewhat cleaner way
to retrieve the parent IPU.

So convert to synchronous registration for the VDIC and IC task
sub-devices, at the time a CSI sub-device is bound. There is no longer
a backing device for them (sd->dev is NULL), but that's ok. Also
set the VDIC/IC sub-device owner as the IPU, so that a reference can
be taken on the IPU module.

Since the VDIC and IC task drivers are no longer platform drivers,
they are now statically linked to imx-media module.
Signed-off-by: default avatarSteve Longerbeam <slongerbeam@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 411c5988
# SPDX-License-Identifier: GPL-2.0
imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o
imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o \
imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o
imx-media-objs += imx-media-dev-common.o
imx-media-common-objs := imx-media-utils.o imx-media-fim.o
imx-media-ic-objs := imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-common.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-capture.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-vdic.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-ic.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
......
......@@ -4,8 +4,6 @@
*
* Copyright (c) 2014-2016 Mentor Graphics Inc.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "imx-media.h"
......@@ -20,23 +18,25 @@ static struct imx_ic_ops *ic_ops[IC_NUM_OPS] = {
[IC_TASK_VIEWFINDER] = &imx_ic_prpencvf_ops,
};
static int imx_ic_probe(struct platform_device *pdev)
struct v4l2_subdev *imx_media_ic_register(struct imx_media_dev *imxmd,
struct device *ipu_dev,
struct ipu_soc *ipu,
u32 grp_id)
{
struct imx_media_ipu_internal_sd_pdata *pdata;
struct v4l2_device *v4l2_dev = &imxmd->v4l2_dev;
struct imx_ic_priv *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
platform_set_drvdata(pdev, &priv->sd);
priv->dev = &pdev->dev;
priv->ipu_dev = ipu_dev;
priv->ipu = ipu;
priv->md = imxmd;
/* get our ipu_id, grp_id and IC task id */
pdata = priv->dev->platform_data;
priv->ipu_id = pdata->ipu_id;
switch (pdata->grp_id) {
/* get our IC task id */
switch (grp_id) {
case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
priv->task_id = IC_TASK_PRP;
break;
......@@ -47,7 +47,7 @@ static int imx_ic_probe(struct platform_device *pdev)
priv->task_id = IC_TASK_VIEWFINDER;
break;
default:
return -EINVAL;
return ERR_PTR(-EINVAL);
}
v4l2_subdev_init(&priv->sd, ic_ops[priv->task_id]->subdev_ops);
......@@ -55,55 +55,35 @@ static int imx_ic_probe(struct platform_device *pdev)
priv->sd.internal_ops = ic_ops[priv->task_id]->internal_ops;
priv->sd.entity.ops = ic_ops[priv->task_id]->entity_ops;
priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
priv->sd.dev = &pdev->dev;
priv->sd.owner = THIS_MODULE;
priv->sd.owner = ipu_dev->driver->owner;
priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
priv->sd.grp_id = pdata->grp_id;
strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
priv->sd.grp_id = grp_id;
imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
priv->sd.grp_id, ipu_get_num(ipu));
ret = ic_ops[priv->task_id]->init(priv);
if (ret)
return ret;
return ERR_PTR(ret);
ret = v4l2_async_register_subdev(&priv->sd);
if (ret)
ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd);
if (ret) {
ic_ops[priv->task_id]->remove(priv);
return ERR_PTR(ret);
}
return ret;
return &priv->sd;
}
static int imx_ic_remove(struct platform_device *pdev)
int imx_media_ic_unregister(struct v4l2_subdev *sd)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct imx_ic_priv *priv = container_of(sd, struct imx_ic_priv, sd);
v4l2_info(sd, "Removing\n");
ic_ops[priv->task_id]->remove(priv);
v4l2_async_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
return 0;
}
static const struct platform_device_id imx_ic_ids[] = {
{ .name = "imx-ipuv3-ic" },
{ },
};
MODULE_DEVICE_TABLE(platform, imx_ic_ids);
static struct platform_driver imx_ic_driver = {
.probe = imx_ic_probe,
.remove = imx_ic_remove,
.id_table = imx_ic_ids,
.driver = {
.name = "imx-ipuv3-ic",
},
};
module_platform_driver(imx_ic_driver);
MODULE_DESCRIPTION("i.MX IC subdev driver");
MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx-ipuv3-ic");
......@@ -35,16 +35,12 @@
#define S_ALIGN 1 /* multiple of 2 */
struct prp_priv {
struct imx_media_dev *md;
struct imx_ic_priv *ic_priv;
struct media_pad pad[PRP_NUM_PADS];
/* lock to protect all members below */
struct mutex lock;
/* IPU units we require */
struct ipu_soc *ipu;
struct v4l2_subdev *src_sd;
struct v4l2_subdev *sink_sd_prpenc;
struct v4l2_subdev *sink_sd_prpvf;
......@@ -62,7 +58,7 @@ static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
return ic_priv->prp_priv;
return ic_priv->task_priv;
}
static int prp_start(struct prp_priv *priv)
......@@ -70,12 +66,10 @@ static int prp_start(struct prp_priv *priv)
struct imx_ic_priv *ic_priv = priv->ic_priv;
bool src_is_vdic;
priv->ipu = priv->md->ipu[ic_priv->ipu_id];
/* set IC to receive from CSI or VDI depending on source */
src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
ipu_set_ic_src_mux(priv->ipu, priv->csi_id, src_is_vdic);
ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic);
return 0;
}
......@@ -216,12 +210,12 @@ static int prp_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
struct prp_priv *priv = ic_priv->prp_priv;
struct prp_priv *priv = ic_priv->task_priv;
struct v4l2_subdev *remote_sd;
int ret = 0;
dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
local->entity->name);
dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
ic_priv->sd.name, remote->entity->name, local->entity->name);
remote_sd = media_entity_to_v4l2_subdev(remote->entity);
......@@ -295,7 +289,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
struct prp_priv *priv = ic_priv->prp_priv;
struct prp_priv *priv = ic_priv->task_priv;
struct v4l2_subdev *csi;
int ret;
......@@ -304,7 +298,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
if (ret)
return ret;
csi = imx_media_find_upstream_subdev(priv->md, &ic_priv->sd.entity,
csi = imx_media_find_upstream_subdev(ic_priv->md, &ic_priv->sd.entity,
IMX_MEDIA_GRP_ID_IPU_CSI);
if (IS_ERR(csi))
csi = NULL;
......@@ -351,7 +345,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
static int prp_s_stream(struct v4l2_subdev *sd, int enable)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
struct prp_priv *priv = ic_priv->prp_priv;
struct prp_priv *priv = ic_priv->task_priv;
int ret = 0;
mutex_lock(&priv->lock);
......@@ -368,7 +362,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF");
dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
enable ? "ON" : "OFF");
if (enable)
ret = prp_start(priv);
......@@ -440,9 +435,6 @@ static int prp_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
/* get media device */
priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
for (i = 0; i < PRP_NUM_PADS; i++) {
priv->pad[i].flags = (i == PRP_SINK_PAD) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
......@@ -494,12 +486,12 @@ static int prp_init(struct imx_ic_priv *ic_priv)
{
struct prp_priv *priv;
priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
mutex_init(&priv->lock);
ic_priv->prp_priv = priv;
ic_priv->task_priv = priv;
priv->ic_priv = ic_priv;
return 0;
......@@ -507,7 +499,7 @@ static int prp_init(struct imx_ic_priv *ic_priv)
static void prp_remove(struct imx_ic_priv *ic_priv)
{
struct prp_priv *priv = ic_priv->prp_priv;
struct prp_priv *priv = ic_priv->task_priv;
mutex_destroy(&priv->lock);
}
......
......@@ -50,7 +50,6 @@
#define S_ALIGN 1 /* multiple of 2 */
struct prp_priv {
struct imx_media_dev *md;
struct imx_ic_priv *ic_priv;
struct media_pad pad[PRPENCVF_NUM_PADS];
/* the video device at output pad */
......@@ -60,7 +59,6 @@ struct prp_priv {
struct mutex lock;
/* IPU units we require */
struct ipu_soc *ipu;
struct ipu_ic *ic;
struct ipuv3_channel *out_ch;
struct ipuv3_channel *rot_in_ch;
......@@ -156,9 +154,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch;
int ret, task = ic_priv->task_id;
priv->ipu = priv->md->ipu[ic_priv->ipu_id];
ic = ipu_ic_get(priv->ipu, task);
ic = ipu_ic_get(ic_priv->ipu, task);
if (IS_ERR(ic)) {
v4l2_err(&ic_priv->sd, "failed to get IC\n");
ret = PTR_ERR(ic);
......@@ -166,7 +162,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->ic = ic;
out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch);
out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].out_ch);
if (IS_ERR(out_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].out_ch);
......@@ -175,7 +171,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->out_ch = out_ch;
rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch);
rot_in_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_in_ch);
if (IS_ERR(rot_in_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].rot_in_ch);
......@@ -184,7 +180,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->rot_in_ch = rot_in_ch;
rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch);
rot_out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_out_ch);
if (IS_ERR(rot_out_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].rot_out_ch);
......@@ -464,13 +460,13 @@ static int prp_setup_rotation(struct prp_priv *priv)
incc = priv->cc[PRPENCVF_SINK_PAD];
outcc = vdev->cc;
ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0],
ret = imx_media_alloc_dma_buf(ic_priv->md, &priv->rot_buf[0],
outfmt->sizeimage);
if (ret) {
v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret);
return ret;
}
ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[1],
ret = imx_media_alloc_dma_buf(ic_priv->md, &priv->rot_buf[1],
outfmt->sizeimage);
if (ret) {
v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret);
......@@ -543,14 +539,16 @@ static int prp_setup_rotation(struct prp_priv *priv)
unsetup_vb2:
prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED);
free_rot1:
imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
imx_media_free_dma_buf(ic_priv->md, &priv->rot_buf[1]);
free_rot0:
imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
imx_media_free_dma_buf(ic_priv->md, &priv->rot_buf[0]);
return ret;
}
static void prp_unsetup_rotation(struct prp_priv *priv)
{
struct imx_ic_priv *ic_priv = priv->ic_priv;
ipu_ic_task_disable(priv->ic);
ipu_idmac_disable_channel(priv->out_ch);
......@@ -561,8 +559,8 @@ static void prp_unsetup_rotation(struct prp_priv *priv)
ipu_ic_disable(priv->ic);
imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
imx_media_free_dma_buf(ic_priv->md, &priv->rot_buf[0]);
imx_media_free_dma_buf(ic_priv->md, &priv->rot_buf[1]);
}
static int prp_setup_norotation(struct prp_priv *priv)
......@@ -602,7 +600,7 @@ static int prp_setup_norotation(struct prp_priv *priv)
ipu_cpmem_dump(priv->out_ch);
ipu_ic_dump(priv->ic);
ipu_dump(priv->ipu);
ipu_dump(ic_priv->ipu);
ipu_ic_enable(priv->ic);
......@@ -654,7 +652,7 @@ static int prp_start(struct prp_priv *priv)
outfmt = &vdev->fmt.fmt.pix;
ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf,
ret = imx_media_alloc_dma_buf(ic_priv->md, &priv->underrun_buf,
outfmt->sizeimage);
if (ret)
goto out_put_ipu;
......@@ -674,10 +672,10 @@ static int prp_start(struct prp_priv *priv)
if (ret)
goto out_free_underrun;
priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu,
priv->nfb4eof_irq = ipu_idmac_channel_irq(ic_priv->ipu,
priv->out_ch,
IPU_IRQ_NFB4EOF);
ret = devm_request_irq(ic_priv->dev, priv->nfb4eof_irq,
ret = devm_request_irq(ic_priv->ipu_dev, priv->nfb4eof_irq,
prp_nfb4eof_interrupt, 0,
"imx-ic-prp-nfb4eof", priv);
if (ret) {
......@@ -688,12 +686,12 @@ static int prp_start(struct prp_priv *priv)
if (ipu_rot_mode_is_irt(priv->rot_mode))
priv->eof_irq = ipu_idmac_channel_irq(
priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF);
ic_priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF);
else
priv->eof_irq = ipu_idmac_channel_irq(
priv->ipu, priv->out_ch, IPU_IRQ_EOF);
ic_priv->ipu, priv->out_ch, IPU_IRQ_EOF);
ret = devm_request_irq(ic_priv->dev, priv->eof_irq,
ret = devm_request_irq(ic_priv->ipu_dev, priv->eof_irq,
prp_eof_interrupt, 0,
"imx-ic-prp-eof", priv);
if (ret) {
......@@ -718,13 +716,13 @@ static int prp_start(struct prp_priv *priv)
return 0;
out_free_eof_irq:
devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv);
out_free_nfb4eof_irq:
devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv);
out_unsetup:
prp_unsetup(priv, VB2_BUF_STATE_QUEUED);
out_free_underrun:
imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
imx_media_free_dma_buf(ic_priv->md, &priv->underrun_buf);
out_put_ipu:
prp_put_ipu_resources(priv);
return ret;
......@@ -756,12 +754,12 @@ static void prp_stop(struct prp_priv *priv)
v4l2_warn(&ic_priv->sd,
"upstream stream off failed: %d\n", ret);
devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv);
devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv);
prp_unsetup(priv, VB2_BUF_STATE_ERROR);
imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
imx_media_free_dma_buf(ic_priv->md, &priv->underrun_buf);
/* cancel the EOF timeout timer */
del_timer_sync(&priv->eof_timeout_timer);
......@@ -1011,8 +1009,8 @@ static int prp_link_setup(struct media_entity *entity,
struct v4l2_subdev *remote_sd;
int ret = 0;
dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
local->entity->name);
dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
ic_priv->sd.name, remote->entity->name, local->entity->name);
mutex_lock(&priv->lock);
......@@ -1178,7 +1176,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF");
dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
enable ? "ON" : "OFF");
if (enable)
ret = prp_start(priv);
......@@ -1238,12 +1237,10 @@ static int prp_s_frame_interval(struct v4l2_subdev *sd,
static int prp_registered(struct v4l2_subdev *sd)
{
struct prp_priv *priv = sd_to_priv(sd);
struct imx_ic_priv *ic_priv = priv->ic_priv;
int i, ret;
u32 code;
/* get media device */
priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
for (i = 0; i < PRPENCVF_NUM_PADS; i++) {
priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
......@@ -1270,7 +1267,7 @@ static int prp_registered(struct v4l2_subdev *sd)
if (ret)
return ret;
ret = imx_media_add_video_device(priv->md, priv->vdev);
ret = imx_media_add_video_device(ic_priv->md, priv->vdev);
if (ret)
goto unreg;
......@@ -1325,7 +1322,7 @@ static int prp_init(struct imx_ic_priv *ic_priv)
{
struct prp_priv *priv;
priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......@@ -1335,7 +1332,8 @@ static int prp_init(struct imx_ic_priv *ic_priv)
spin_lock_init(&priv->irqlock);
timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0);
priv->vdev = imx_media_capture_device_init(&ic_priv->sd,
priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev,
&ic_priv->sd,
PRPENCVF_SRC_PAD);
if (IS_ERR(priv->vdev))
return PTR_ERR(priv->vdev);
......
......@@ -10,11 +10,11 @@
#include <media/v4l2-subdev.h>
struct imx_ic_priv {
struct device *dev;
struct device *ipu_dev;
struct ipu_soc *ipu;
struct imx_media_dev *md;
struct v4l2_subdev sd;
int ipu_id;
int task_id;
void *prp_priv;
void *task_priv;
};
......@@ -29,6 +29,5 @@ struct imx_ic_ops {
extern struct imx_ic_ops imx_ic_prp_ops;
extern struct imx_ic_ops imx_ic_prpencvf_ops;
extern struct imx_ic_ops imx_ic_pp_ops;
#endif
......@@ -798,18 +798,19 @@ void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev)
EXPORT_SYMBOL_GPL(imx_media_capture_device_unregister);
struct imx_media_video_dev *
imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad)
imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
int pad)
{
struct capture_priv *priv;
struct video_device *vfd;
priv = devm_kzalloc(src_sd->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
priv->src_sd = src_sd;
priv->src_sd_pad = pad;
priv->dev = src_sd->dev;
priv->dev = dev;
mutex_init(&priv->mutex);
spin_lock_init(&priv->q_lock);
......
......@@ -1983,7 +1983,7 @@ static int imx_csi_probe(struct platform_device *pdev)
imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
priv->sd.grp_id, ipu_get_num(priv->ipu));
priv->vdev = imx_media_capture_device_init(&priv->sd,
priv->vdev = imx_media_capture_device_init(priv->sd.dev, &priv->sd,
CSI_SRC_PAD_IDMAC);
if (IS_ERR(priv->vdev))
return PTR_ERR(priv->vdev);
......
......@@ -28,111 +28,24 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
return container_of(n, struct imx_media_dev, notifier);
}
/*
* Adds a subdev to the root notifier's async subdev list. If fwnode is
* non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
* otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
* of the given platform_device. This is called during driver load when
* forming the async subdev list.
*/
int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
struct fwnode_handle *fwnode,
struct platform_device *pdev)
{
struct device_node *np = to_of_node(fwnode);
struct imx_media_async_subdev *imxasd;
struct v4l2_async_subdev *asd;
const char *devname = NULL;
int ret;
if (fwnode) {
asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
fwnode,
sizeof(*imxasd));
} else {
devname = dev_name(&pdev->dev);
asd = v4l2_async_notifier_add_devname_subdev(&imxmd->notifier,
devname,
sizeof(*imxasd));
}
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
if (ret == -EEXIST) {
if (np)
dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
__func__, np);
else
dev_dbg(imxmd->md.dev, "%s: already added %s\n",
__func__, devname);
}
return ret;
}
imxasd = to_imx_media_asd(asd);
if (devname)
imxasd->pdev = pdev;
if (np)
dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n",
__func__, np);
else
dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n",
__func__, devname);
return 0;
}
/*
* get IPU from this CSI and add it to the list of IPUs
* the media driver will control.
*/
static int imx_media_get_ipu(struct imx_media_dev *imxmd,
struct v4l2_subdev *csi_sd)
{
struct ipu_soc *ipu;
int ipu_id;
ipu = dev_get_drvdata(csi_sd->dev->parent);
if (!ipu) {
v4l2_err(&imxmd->v4l2_dev,
"CSI %s has no parent IPU!\n", csi_sd->name);
return -ENODEV;
}
ipu_id = ipu_get_num(ipu);
if (ipu_id > 1) {
v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id);
return -ENODEV;
}
if (!imxmd->ipu[ipu_id])
imxmd->ipu[ipu_id] = ipu;
return 0;
}
/* async subdev bound notifier */
int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
int ret = 0;
mutex_lock(&imxmd->mutex);
int ret;
if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) {
ret = imx_media_get_ipu(imxmd, sd);
/* register the IPU internal subdevs */
ret = imx_media_register_ipu_internal_subdevs(imxmd, sd);
if (ret)
goto out;
return ret;
}
v4l2_info(&imxmd->v4l2_dev, "subdev %s bound\n", sd->name);
out:
mutex_unlock(&imxmd->mutex);
return ret;
return 0;
}
/*
......@@ -143,7 +56,6 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
struct v4l2_subdev *sd;
int ret;
list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
switch (sd->grp_id) {
......@@ -151,22 +63,15 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
case IMX_MEDIA_GRP_ID_IPU_CSI0:
case IMX_MEDIA_GRP_ID_IPU_CSI1:
ret = imx_media_create_ipu_internal_links(imxmd, sd);
if (ret)
return ret;
/*
* the CSIs straddle between the external and the IPU
* internal entities, so create the external links
* to the CSI sink pads.
* links have already been created for the
* sync-registered subdevs.
*/
if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI)
imx_media_create_csi_of_links(imxmd, sd);
break;
case IMX_MEDIA_GRP_ID_IPU_CSI0:
case IMX_MEDIA_GRP_ID_IPU_CSI1:
case IMX_MEDIA_GRP_ID_CSI:
imx_media_create_csi_of_links(imxmd, sd);
break;
default:
/*
......@@ -476,12 +381,10 @@ static int imx_media_probe(struct platform_device *pdev)
ret = imx_media_dev_notifier_register(imxmd);
if (ret)
goto del_int;
goto cleanup;
return 0;
del_int:
imx_media_remove_ipu_internal_subdevs(imxmd);
cleanup:
v4l2_async_notifier_cleanup(&imxmd->notifier);
v4l2_device_unregister(&imxmd->v4l2_dev);
......@@ -498,7 +401,7 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_remove_ipu_internal_subdevs(imxmd);
imx_media_unregister_ipu_internal_subdevs(imxmd);
v4l2_async_notifier_cleanup(&imxmd->notifier);
media_device_unregister(&imxmd->md);
v4l2_device_unregister(&imxmd->v4l2_dev);
......
......@@ -19,6 +19,9 @@
int imx_media_of_add_csi(struct imx_media_dev *imxmd,
struct device_node *csi_np)
{
struct v4l2_async_subdev *asd;
int ret = 0;
if (!of_device_is_available(csi_np)) {
dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
csi_np);
......@@ -26,18 +29,25 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd,
}
/* add CSI fwnode to async notifier */
return imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np),
NULL);
asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
of_fwnode_handle(csi_np),
sizeof(*asd));
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
if (ret == -EEXIST)
dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
__func__, csi_np);
}
return ret;
}
EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
struct device_node *np)
{
bool ipu_found[2] = {false, false};
struct device_node *csi_np;
int i, ret;
u32 ipu_id;
for (i = 0; ; i++) {
csi_np = of_parse_phandle(np, "ports", i);
......@@ -55,31 +65,11 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
/* other error, can't continue */
goto err_out;
}
ret = of_alias_get_id(csi_np->parent, "ipu");
if (ret < 0)
goto err_out;
if (ret > 1) {
ret = -EINVAL;
goto err_out;
}
ipu_id = ret;
if (!ipu_found[ipu_id]) {
ret = imx_media_add_ipu_internal_subdevs(imxmd,
ipu_id);
if (ret)
goto err_out;
}
ipu_found[ipu_id] = true;
}
return 0;
err_out:
imx_media_remove_ipu_internal_subdevs(imxmd);
of_node_put(csi_np);
return ret;
}
......
......@@ -4,13 +4,6 @@
*
* Copyright (c) 2017 Mentor Graphics Inc.
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
......@@ -65,12 +58,12 @@ struct vdic_pipeline_ops {
#define S_ALIGN 1 /* multiple of 2 */
struct vdic_priv {
struct device *dev;
struct ipu_soc *ipu;
struct device *ipu_dev;
struct ipu_soc *ipu;
struct imx_media_dev *md;
struct v4l2_subdev sd;
struct media_pad pad[VDIC_NUM_PADS];
int ipu_id;
/* lock to protect all members below */
struct mutex lock;
......@@ -145,8 +138,6 @@ static int vdic_get_ipu_resources(struct vdic_priv *priv)
struct ipuv3_channel *ch;
struct ipu_vdi *vdi;
priv->ipu = priv->md->ipu[priv->ipu_id];
vdi = ipu_vdi_get(priv->ipu);
if (IS_ERR(vdi)) {
v4l2_err(&priv->sd, "failed to get VDIC\n");
......@@ -511,7 +502,8 @@ static int vdic_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
dev_dbg(priv->dev, "stream %s\n", enable ? "ON" : "OFF");
dev_dbg(priv->ipu_dev, "%s: stream %s\n", sd->name,
enable ? "ON" : "OFF");
if (enable)
ret = vdic_start(priv);
......@@ -686,8 +678,8 @@ static int vdic_link_setup(struct media_entity *entity,
struct v4l2_subdev *remote_sd;
int ret = 0;
dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name,
local->entity->name);
dev_dbg(priv->ipu_dev, "%s: link setup %s -> %s",
sd->name, remote->entity->name, local->entity->name);
mutex_lock(&priv->lock);
......@@ -860,9 +852,6 @@ static int vdic_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
/* get media device */
priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
for (i = 0; i < VDIC_NUM_PADS; i++) {
priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ?
MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
......@@ -934,77 +923,55 @@ static const struct v4l2_subdev_internal_ops vdic_internal_ops = {
.unregistered = vdic_unregistered,
};
static int imx_vdic_probe(struct platform_device *pdev)
struct v4l2_subdev *imx_media_vdic_register(struct imx_media_dev *imxmd,
struct device *ipu_dev,
struct ipu_soc *ipu,
u32 grp_id)
{
struct imx_media_ipu_internal_sd_pdata *pdata;
struct v4l2_device *v4l2_dev = &imxmd->v4l2_dev;
struct vdic_priv *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
platform_set_drvdata(pdev, &priv->sd);
priv->dev = &pdev->dev;
pdata = priv->dev->platform_data;
priv->ipu_id = pdata->ipu_id;
priv->ipu_dev = ipu_dev;
priv->ipu = ipu;
priv->md = imxmd;
v4l2_subdev_init(&priv->sd, &vdic_subdev_ops);
v4l2_set_subdevdata(&priv->sd, priv);
priv->sd.internal_ops = &vdic_internal_ops;
priv->sd.entity.ops = &vdic_entity_ops;
priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
priv->sd.dev = &pdev->dev;
priv->sd.owner = THIS_MODULE;
priv->sd.owner = ipu_dev->driver->owner;
priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
/* get our group id */
priv->sd.grp_id = pdata->grp_id;
strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
priv->sd.grp_id = grp_id;
imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
priv->sd.grp_id, ipu_get_num(ipu));
mutex_init(&priv->lock);
ret = v4l2_async_register_subdev(&priv->sd);
ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd);
if (ret)
goto free;
return 0;
return &priv->sd;
free:
mutex_destroy(&priv->lock);
return ret;
return ERR_PTR(ret);
}
static int imx_vdic_remove(struct platform_device *pdev)
int imx_media_vdic_unregister(struct v4l2_subdev *sd)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
v4l2_info(sd, "Removing\n");
v4l2_async_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd);
mutex_destroy(&priv->lock);
media_entity_cleanup(&sd->entity);
return 0;
}
static const struct platform_device_id imx_vdic_ids[] = {
{ .name = "imx-ipuv3-vdic" },
{ },
};
MODULE_DEVICE_TABLE(platform, imx_vdic_ids);
static struct platform_driver imx_vdic_driver = {
.probe = imx_vdic_probe,
.remove = imx_vdic_remove,
.id_table = imx_vdic_ids,
.driver = {
.name = "imx-ipuv3-vdic",
},
};
module_platform_driver(imx_vdic_driver);
MODULE_DESCRIPTION("i.MX VDIC subdev driver");
MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx-ipuv3-vdic");
......@@ -15,6 +15,19 @@
#include <media/videobuf2-dma-contig.h>
#include <video/imx-ipu-v3.h>
/*
* Enumeration of the IPU internal sub-devices
*/
enum {
IPU_CSI0 = 0,
IPU_CSI1,
IPU_VDIC,
IPU_IC_PRP,
IPU_IC_PRPENC,
IPU_IC_PRPVF,
NUM_IPU_SUBDEVS,
};
/*
* Pad definitions for the subdevs with multiple source or
* sink pads
......@@ -111,25 +124,6 @@ struct imx_media_pad_vdev {
struct list_head list;
};
struct imx_media_ipu_internal_sd_pdata {
char sd_name[V4L2_SUBDEV_NAME_SIZE];
u32 grp_id;
int ipu_id;
};
struct imx_media_async_subdev {
/* the base asd - must be first in this struct */
struct v4l2_async_subdev asd;
/* the platform device of IPU-internal subdevs */
struct platform_device *pdev;
};
static inline struct imx_media_async_subdev *
to_imx_media_asd(struct v4l2_async_subdev *asd)
{
return container_of(asd, struct imx_media_async_subdev, asd);
}
struct imx_media_dev {
struct media_device md;
struct v4l2_device v4l2_dev;
......@@ -142,11 +136,11 @@ struct imx_media_dev {
/* master video device list */
struct list_head vdev_list;
/* IPUs this media driver control, valid after subdevs bound */
struct ipu_soc *ipu[2];
/* for async subdev registration */
struct v4l2_async_notifier notifier;
/* the IPU internal subdev's registered synchronously */
struct v4l2_subdev *sync_sd[2][NUM_IPU_SUBDEVS];
};
enum codespace_sel {
......@@ -221,10 +215,6 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
bool on);
/* imx-media-dev.c */
int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
struct fwnode_handle *fwnode,
struct platform_device *pdev);
int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd);
......@@ -248,11 +238,9 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim);
/* imx-media-internal-sd.c */
int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
int ipu_id);
int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *sd);
void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd);
int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
struct v4l2_subdev *csi);
void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd);
/* imx-media-of.c */
int imx_media_add_of_subdevs(struct imx_media_dev *dev,
......@@ -264,9 +252,24 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
int imx_media_of_add_csi(struct imx_media_dev *imxmd,
struct device_node *csi_np);
/* imx-media-vdic.c */
struct v4l2_subdev *imx_media_vdic_register(struct imx_media_dev *imxmd,
struct device *ipu_dev,
struct ipu_soc *ipu,
u32 grp_id);
int imx_media_vdic_unregister(struct v4l2_subdev *sd);
/* imx-ic-common.c */
struct v4l2_subdev *imx_media_ic_register(struct imx_media_dev *imxmd,
struct device *ipu_dev,
struct ipu_soc *ipu,
u32 grp_id);
int imx_media_ic_unregister(struct v4l2_subdev *sd);
/* imx-media-capture.c */
struct imx_media_video_dev *
imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad);
imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
int pad);
void imx_media_capture_device_remove(struct imx_media_video_dev *vdev);
int imx_media_capture_device_register(struct imx_media_video_dev *vdev);
void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev);
......
......@@ -1292,7 +1292,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI;
snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
csi->vdev = imx_media_capture_device_init(&csi->sd, IMX7_CSI_PAD_SRC);
csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd,
IMX7_CSI_PAD_SRC);
if (IS_ERR(csi->vdev))
return PTR_ERR(csi->vdev);
......
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