mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
media: rockchip: isp1: add pipeline power management
Change-Id: I0021482560db18ae50c78e91a590c4ae3d729761 Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
This commit is contained in:
@@ -1715,12 +1715,18 @@ int rkisp1_fh_open(struct file *filp)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(filp);
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct video_device *vdev = &stream->vnode.vdev;
|
||||
int ret;
|
||||
|
||||
ret = v4l2_fh_open(filp);
|
||||
if (!ret) {
|
||||
if (atomic_inc_return(&dev->open_cnt) == 1)
|
||||
rkisp1_dma_attach_device(dev);
|
||||
|
||||
ret = dev->pipe.pm_use(&vdev->entity, 1);
|
||||
if (ret < 0)
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"set pipeline power failed %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1730,12 +1736,19 @@ int rkisp1_fop_release(struct file *file)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct video_device *vdev = &stream->vnode.vdev;
|
||||
int ret;
|
||||
|
||||
ret = vb2_fop_release(file);
|
||||
if (!ret) {
|
||||
ret = dev->pipe.pm_use(&vdev->entity, 0);
|
||||
if (ret < 0)
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"set pipeline power failed %d\n", ret);
|
||||
|
||||
if (atomic_dec_return(&dev->open_cnt) == 0)
|
||||
rkisp1_dma_detach_device(dev);
|
||||
if (atomic_dec_return(&dev->open_cnt) == 0)
|
||||
rkisp1_dma_detach_device(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -127,47 +127,6 @@ static int __isp_pipeline_prepare(struct rkisp1_pipeline *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __subdev_set_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sd)
|
||||
return -ENXIO;
|
||||
|
||||
ret = v4l2_subdev_call(sd, core, s_power, on);
|
||||
|
||||
return ret != -ENOIOCTLCMD ? ret : 0;
|
||||
}
|
||||
|
||||
static int __isp_pipeline_s_power(struct rkisp1_pipeline *p, bool on)
|
||||
{
|
||||
struct rkisp1_device *dev = container_of(p, struct rkisp1_device, pipe);
|
||||
int i, ret;
|
||||
|
||||
if (on) {
|
||||
__subdev_set_power(&dev->isp_sdev.sd, true);
|
||||
|
||||
for (i = p->num_subdevs - 1; i >= 0; --i) {
|
||||
ret = __subdev_set_power(p->subdevs[i], true);
|
||||
if (ret < 0 && ret != -ENXIO)
|
||||
goto err_power_off;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < p->num_subdevs; ++i)
|
||||
__subdev_set_power(p->subdevs[i], false);
|
||||
|
||||
__subdev_set_power(&dev->isp_sdev.sd, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off:
|
||||
for (++i; i < p->num_subdevs; ++i)
|
||||
__subdev_set_power(p->subdevs[i], false);
|
||||
__subdev_set_power(&dev->isp_sdev.sd, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __isp_pipeline_s_isp_clk(struct rkisp1_pipeline *p)
|
||||
{
|
||||
struct rkisp1_device *dev = container_of(p, struct rkisp1_device, pipe);
|
||||
@@ -243,22 +202,14 @@ static int rkisp1_pipeline_open(struct rkisp1_pipeline *p,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = __isp_pipeline_s_power(p, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_pipeline_close(struct rkisp1_pipeline *p)
|
||||
{
|
||||
int ret;
|
||||
atomic_dec(&p->power_cnt);
|
||||
|
||||
if (atomic_dec_return(&p->power_cnt) > 0)
|
||||
return 0;
|
||||
ret = __isp_pipeline_s_power(p, 0);
|
||||
|
||||
return ret == -ENXIO ? 0 : ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -305,6 +256,125 @@ err_stream_off:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkisp1_pipeline_pm_use_count(struct media_entity *entity)
|
||||
{
|
||||
struct media_entity_graph graph;
|
||||
int use = 0;
|
||||
|
||||
media_entity_graph_walk_start(&graph, entity);
|
||||
|
||||
while ((entity = media_entity_graph_walk_next(&graph))) {
|
||||
if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
|
||||
use += entity->use_count;
|
||||
}
|
||||
|
||||
return use;
|
||||
}
|
||||
|
||||
static int rkisp1_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
|
||||
? media_entity_to_v4l2_subdev(entity) : NULL;
|
||||
|
||||
if (entity->use_count == 0 && change > 0 && subdev) {
|
||||
ret = v4l2_subdev_call(subdev, core, s_power, 1);
|
||||
if (ret < 0 && ret != -ENOIOCTLCMD)
|
||||
return ret;
|
||||
}
|
||||
|
||||
entity->use_count += change;
|
||||
WARN_ON(entity->use_count < 0);
|
||||
|
||||
if (entity->use_count == 0 && change < 0 && subdev)
|
||||
v4l2_subdev_call(subdev, core, s_power, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_pipeline_pm_power(struct media_entity *entity, int change)
|
||||
{
|
||||
struct media_entity_graph graph;
|
||||
struct media_entity *first = entity;
|
||||
int ret = 0;
|
||||
|
||||
if (!change)
|
||||
return 0;
|
||||
|
||||
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)
|
||||
ret = rkisp1_pipeline_pm_power_one(entity, change);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
media_entity_graph_walk_start(&graph, first);
|
||||
|
||||
while ((first = media_entity_graph_walk_next(&graph)) && first != entity)
|
||||
if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
|
||||
rkisp1_pipeline_pm_power_one(first, -change);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkisp1_pipeline_pm_use(struct media_entity *entity, int use)
|
||||
{
|
||||
int change = use ? 1 : -1;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&entity->parent->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 = rkisp1_pipeline_pm_power(entity, change);
|
||||
if (ret < 0)
|
||||
entity->use_count -= change;
|
||||
|
||||
mutex_unlock(&entity->parent->graph_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkisp1_pipeline_link_notify(struct media_link *link, u32 flags,
|
||||
unsigned int notification)
|
||||
{
|
||||
struct media_entity *source = link->source->entity;
|
||||
struct media_entity *sink = link->sink->entity;
|
||||
int source_use = rkisp1_pipeline_pm_use_count(source);
|
||||
int sink_use = rkisp1_pipeline_pm_use_count(sink);
|
||||
int ret;
|
||||
|
||||
if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
|
||||
!(flags & MEDIA_LNK_FL_ENABLED)) {
|
||||
/* Powering off entities is assumed to never fail. */
|
||||
rkisp1_pipeline_pm_power(source, -sink_use);
|
||||
rkisp1_pipeline_pm_power(sink, -source_use);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
|
||||
(flags & MEDIA_LNK_FL_ENABLED)) {
|
||||
ret = rkisp1_pipeline_pm_power(source, sink_use);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rkisp1_pipeline_pm_power(sink, source_use);
|
||||
if (ret < 0)
|
||||
rkisp1_pipeline_pm_power(source, -sink_use);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************** media controller *******************************/
|
||||
/* See http://opensource.rock-chips.com/wiki_Rockchip-isp1 for Topology */
|
||||
|
||||
@@ -1100,6 +1170,7 @@ static int rkisp1_plat_probe(struct platform_device *pdev)
|
||||
isp_dev->pipe.open = rkisp1_pipeline_open;
|
||||
isp_dev->pipe.close = rkisp1_pipeline_close;
|
||||
isp_dev->pipe.set_stream = rkisp1_pipeline_set_stream;
|
||||
isp_dev->pipe.pm_use = rkisp1_pipeline_pm_use;
|
||||
|
||||
rkisp1_stream_init(isp_dev, RKISP1_STREAM_SP);
|
||||
rkisp1_stream_init(isp_dev, RKISP1_STREAM_MP);
|
||||
@@ -1121,6 +1192,7 @@ static int rkisp1_plat_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
isp_dev->media_dev.link_notify = rkisp1_pipeline_link_notify;
|
||||
ret = media_device_register(&isp_dev->media_dev);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev, "Failed to register media device: %d\n",
|
||||
|
||||
@@ -105,6 +105,7 @@ struct rkisp1_pipeline {
|
||||
struct media_entity *me, bool prepare);
|
||||
int (*close)(struct rkisp1_pipeline *p);
|
||||
int (*set_stream)(struct rkisp1_pipeline *p, bool on);
|
||||
int (*pm_use)(struct media_entity *entity, int use);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user