aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/omap3isp/isp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/omap3isp/isp.c')
-rw-r--r--drivers/media/platform/omap3isp/isp.c306
1 files changed, 198 insertions, 108 deletions
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 56e683b19a73..0bcfa553c1aa 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -683,15 +683,15 @@ static irqreturn_t isp_isr(int irq, void *_isp)
*
* Return the total number of users of all video device nodes in the pipeline.
*/
-static int isp_pipeline_pm_use_count(struct media_entity *entity)
+static int isp_pipeline_pm_use_count(struct media_entity *entity,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
int use = 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ while ((entity = media_entity_graph_walk_next(graph))) {
+ if (is_media_entity_v4l2_io(entity))
use += entity->use_count;
}
@@ -714,7 +714,7 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
struct v4l2_subdev *subdev;
int ret;
- subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+ subdev = is_media_entity_v4l2_subdev(entity)
? media_entity_to_v4l2_subdev(entity) : NULL;
if (entity->use_count == 0 && change > 0 && subdev != NULL) {
@@ -742,29 +742,29 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
*
* Return 0 on success or a negative error code on failure.
*/
-static int isp_pipeline_pm_power(struct media_entity *entity, int change)
+static int isp_pipeline_pm_power(struct media_entity *entity, int change,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
struct media_entity *first = entity;
int ret = 0;
if (!change)
return 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while (!ret && (entity = media_entity_graph_walk_next(&graph)))
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ while (!ret && (entity = media_entity_graph_walk_next(graph)))
+ if (is_media_entity_v4l2_subdev(entity))
ret = isp_pipeline_pm_power_one(entity, change);
if (!ret)
- return 0;
+ return ret;
- media_entity_graph_walk_start(&graph, first);
+ media_entity_graph_walk_start(graph, first);
- while ((first = media_entity_graph_walk_next(&graph))
+ while ((first = media_entity_graph_walk_next(graph))
&& first != entity)
- if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+ if (is_media_entity_v4l2_subdev(first))
isp_pipeline_pm_power_one(first, -change);
return ret;
@@ -782,23 +782,24 @@ static int isp_pipeline_pm_power(struct media_entity *entity, int change)
* off is assumed to never fail. No failure can occur when the use parameter is
* set to 0.
*/
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use,
+ struct media_entity_graph *graph)
{
int change = use ? 1 : -1;
int ret;
- mutex_lock(&entity->parent->graph_mutex);
+ mutex_lock(&entity->graph_obj.mdev->graph_mutex);
/* Apply use count to node. */
entity->use_count += change;
WARN_ON(entity->use_count < 0);
/* Apply power change to connected non-nodes. */
- ret = isp_pipeline_pm_power(entity, change);
+ ret = isp_pipeline_pm_power(entity, change, graph);
if (ret < 0)
entity->use_count -= change;
- mutex_unlock(&entity->parent->graph_mutex);
+ mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
return ret;
}
@@ -820,35 +821,49 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
unsigned int notification)
{
+ struct media_entity_graph *graph =
+ &container_of(link->graph_obj.mdev, struct isp_device,
+ media_dev)->pm_count_graph;
struct media_entity *source = link->source->entity;
struct media_entity *sink = link->sink->entity;
- int source_use = isp_pipeline_pm_use_count(source);
- int sink_use = isp_pipeline_pm_use_count(sink);
- int ret;
+ int source_use;
+ int sink_use;
+ int ret = 0;
+
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+ ret = media_entity_graph_walk_init(graph,
+ link->graph_obj.mdev);
+ if (ret)
+ return ret;
+ }
+
+ source_use = isp_pipeline_pm_use_count(source, graph);
+ sink_use = isp_pipeline_pm_use_count(sink, graph);
if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
!(flags & MEDIA_LNK_FL_ENABLED)) {
/* Powering off entities is assumed to never fail. */
- isp_pipeline_pm_power(source, -sink_use);
- isp_pipeline_pm_power(sink, -source_use);
+ isp_pipeline_pm_power(source, -sink_use, graph);
+ isp_pipeline_pm_power(sink, -source_use, graph);
return 0;
}
if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
(flags & MEDIA_LNK_FL_ENABLED)) {
- ret = isp_pipeline_pm_power(source, sink_use);
+ ret = isp_pipeline_pm_power(source, sink_use, graph);
if (ret < 0)
return ret;
- ret = isp_pipeline_pm_power(sink, source_use);
+ ret = isp_pipeline_pm_power(sink, source_use, graph);
if (ret < 0)
- isp_pipeline_pm_power(source, -sink_use);
-
- return ret;
+ isp_pipeline_pm_power(source, -sink_use, graph);
}
- return 0;
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH)
+ media_entity_graph_walk_cleanup(graph);
+
+ return ret;
}
/* -----------------------------------------------------------------------------
@@ -881,7 +896,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
* starting entities if the pipeline won't start anyway (those entities
* would then likely fail to stop, making the problem worse).
*/
- if (pipe->entities & isp->crashed)
+ if (media_entity_enum_intersects(&pipe->ent_enum, &isp->crashed))
return -EIO;
spin_lock_irqsave(&pipe->lock, flags);
@@ -897,8 +912,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
break;
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -987,8 +1001,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
break;
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -1028,7 +1041,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
isp->stop_failure = true;
if (subdev == &isp->isp_prev.subdev)
- isp->crashed |= 1U << subdev->entity.id;
+ media_entity_enum_set(&isp->crashed,
+ &subdev->entity);
failure = -ETIMEDOUT;
}
}
@@ -1234,7 +1248,7 @@ static int isp_reset(struct isp_device *isp)
}
isp->stop_failure = false;
- isp->crashed = 0;
+ media_entity_enum_zero(&isp->crashed);
return 0;
}
@@ -1645,7 +1659,8 @@ static void __omap3isp_put(struct isp_device *isp, bool save_ctx)
/* Reset the ISP if an entity has failed to stop. This is the
* only way to recover from such conditions.
*/
- if (isp->crashed || isp->stop_failure)
+ if (!media_entity_enum_empty(&isp->crashed) ||
+ isp->stop_failure)
isp_reset(isp);
isp_disable_clocks(isp);
}
@@ -1792,6 +1807,7 @@ static void isp_unregister_entities(struct isp_device *isp)
v4l2_device_unregister(&isp->v4l2_dev);
media_device_unregister(&isp->media_dev);
+ media_device_cleanup(&isp->media_dev);
}
static int isp_link_entity(
@@ -1862,7 +1878,7 @@ static int isp_link_entity(
return -EINVAL;
}
- return media_entity_create_link(entity, i, input, pad, flags);
+ return media_create_pad_link(entity, i, input, pad, flags);
}
static int isp_register_entities(struct isp_device *isp)
@@ -1874,12 +1890,7 @@ static int isp_register_entities(struct isp_device *isp)
sizeof(isp->media_dev.model));
isp->media_dev.hw_revision = isp->revision;
isp->media_dev.link_notify = isp_pipeline_link_notify;
- ret = media_device_register(&isp->media_dev);
- if (ret < 0) {
- dev_err(isp->dev, "%s: Media device registration failed (%d)\n",
- __func__, ret);
- return ret;
- }
+ media_device_init(&isp->media_dev);
isp->v4l2_dev.mdev = &isp->media_dev;
ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
@@ -1930,6 +1941,118 @@ done:
return ret;
}
+/*
+ * isp_create_links() - Create links for internal and external ISP entities
+ * @isp : Pointer to ISP device
+ *
+ * This function creates all links between ISP internal and external entities.
+ *
+ * Return: A negative error code on failure or zero on success. Possible error
+ * codes are those returned by media_create_pad_link().
+ */
+static int isp_create_links(struct isp_device *isp)
+{
+ int ret;
+
+ /* Create links between entities and video nodes. */
+ ret = media_create_pad_link(
+ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &isp->isp_csi2a.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccp2.video_in.video.entity, 0,
+ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+ &isp->isp_ccdc.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.video_in.video.entity, 0,
+ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+ &isp->isp_prev.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_res.video_in.video.entity, 0,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_res.subdev.entity, RESZ_PAD_SOURCE,
+ &isp->isp_res.video_out.video.entity, 0, 0);
+
+ if (ret < 0)
+ return ret;
+
+ /* Create links between entities. */
+ ret = media_create_pad_link(
+ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_aewb.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_af.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_hist.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static void isp_cleanup_modules(struct isp_device *isp)
{
omap3isp_h3a_aewb_cleanup(isp);
@@ -2000,62 +2123,8 @@ static int isp_initialize_modules(struct isp_device *isp)
goto error_h3a_af;
}
- /* Connect the submodules. */
- ret = media_entity_create_link(
- &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_aewb.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_af.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_hist.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap3isp_h3a_af_cleanup(isp);
error_h3a_af:
omap3isp_h3a_aewb_cleanup(isp);
error_h3a_aewb:
@@ -2149,6 +2218,8 @@ static int isp_remove(struct platform_device *pdev)
isp_detach_iommu(isp);
__omap3isp_put(isp, false);
+ media_entity_enum_cleanup(&isp->crashed);
+
return 0;
}
@@ -2278,28 +2349,43 @@ static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
- struct isp_device *isp = container_of(async, struct isp_device,
- notifier);
struct isp_async_subdev *isd =
container_of(asd, struct isp_async_subdev, asd);
- int ret;
-
- ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface);
- if (ret < 0)
- return ret;
isd->sd = subdev;
isd->sd->host_priv = &isd->bus;
- return ret;
+ return 0;
}
static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
{
struct isp_device *isp = container_of(async, struct isp_device,
notifier);
+ struct v4l2_device *v4l2_dev = &isp->v4l2_dev;
+ struct v4l2_subdev *sd;
+ struct isp_bus_cfg *bus;
+ int ret;
+
+ ret = media_entity_enum_init(&isp->crashed, &isp->media_dev);
+ if (ret)
+ return ret;
- return v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
+ /* Only try to link entities whose interface was set on bound */
+ if (sd->host_priv) {
+ bus = (struct isp_bus_cfg *)sd->host_priv;
+ ret = isp_link_entity(isp, &sd->entity, bus->interface);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
+ return media_device_register(&isp->media_dev);
}
/*
@@ -2465,6 +2551,10 @@ static int isp_probe(struct platform_device *pdev)
if (ret < 0)
goto error_modules;
+ ret = isp_create_links(isp);
+ if (ret < 0)
+ goto error_register_entities;
+
isp->notifier.bound = isp_subdev_notifier_bound;
isp->notifier.complete = isp_subdev_notifier_complete;