From bc7584b0b7a99326d31195f81f7494efe9fe0c0f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 31 May 2013 11:37:18 -0300 Subject: [media] exynos4-is: Add struct exynos_video_entity This patch introduces common structure for the video entities to handle all video nodes and media pipelines associated with them in more generic way. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 47da5e049247..fa3886a297ba 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -95,8 +95,8 @@ struct flite_buffer { * struct fimc_lite - fimc lite structure * @pdev: pointer to FIMC-LITE platform device * @dd: SoC specific driver data structure + * @ve: exynos video device entity structure * @v4l2_dev: pointer to top the level v4l2_device - * @vfd: video device node * @fh: v4l2 file handle * @alloc_ctx: videobuf2 memory allocator context * @subdev: FIMC-LITE subdev @@ -130,8 +130,8 @@ struct flite_buffer { struct fimc_lite { struct platform_device *pdev; struct flite_drvdata *dd; + struct exynos_video_entity ve; struct v4l2_device *v4l2_dev; - struct video_device vfd; struct v4l2_fh fh; struct vb2_alloc_ctx *alloc_ctx; struct v4l2_subdev subdev; -- cgit v1.2.3 From 42625fdfbd608f0bdaffaf25e8eb32ef55cddf96 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 31 May 2013 11:37:20 -0300 Subject: [media] exynos4-is: Media graph/video device locking rework Remove driver private video node reference counters and use entity->use_count instead. This makes the video pipelines power handling more similar to the method used in omap3isp driver. Now the graph mutex is taken always after the video mutex, as it is not possible to ensure apposite order at the all modules. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 59 +++++++++++------------- drivers/media/platform/exynos4-is/fimc-core.h | 2 - drivers/media/platform/exynos4-is/fimc-lite.c | 23 +++++---- drivers/media/platform/exynos4-is/fimc-lite.h | 2 - drivers/media/platform/exynos4-is/media-dev.c | 12 +---- 5 files changed, 42 insertions(+), 56 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 07089de6c669..b6055d2b09d6 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -484,7 +484,6 @@ static int fimc_capture_open(struct file *file) dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - fimc_md_graph_lock(ve); mutex_lock(&fimc->lock); if (fimc_m2m_active(fimc)) @@ -502,6 +501,8 @@ static int fimc_capture_open(struct file *file) } if (v4l2_fh_is_singular_file(file)) { + fimc_md_graph_lock(ve); + ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vid_cap.ve.vdev.entity, true); if (ret == 0) @@ -518,18 +519,19 @@ static int fimc_capture_open(struct file *file) if (ret == 0) vc->inh_sensor_ctrls = false; } + if (ret == 0) + ve->vdev.entity.use_count++; + + fimc_md_graph_unlock(ve); if (ret < 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_put_sync(&fimc->pdev->dev); v4l2_fh_release(file); - } else { - fimc->vid_cap.refcnt++; } } unlock: mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(ve); return ret; } @@ -537,26 +539,32 @@ static int fimc_capture_release(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_vid_cap *vc = &fimc->vid_cap; + bool close = v4l2_fh_is_singular_file(file); int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); mutex_lock(&fimc->lock); - if (v4l2_fh_is_singular_file(file)) { - if (vc->streaming) { - media_entity_pipeline_stop(&vc->ve.vdev.entity); - vc->streaming = false; - } + if (close && vc->streaming) { + media_entity_pipeline_stop(&vc->ve.vdev.entity); + vc->streaming = false; + } + + ret = vb2_fop_release(file); + + if (close) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); - fimc->vid_cap.refcnt--; + + fimc_md_graph_lock(&vc->ve); + vc->ve.vdev.entity.use_count--; + fimc_md_graph_unlock(&vc->ve); } pm_runtime_put(&fimc->pdev->dev); - ret = vb2_fop_release(file); mutex_unlock(&fimc->lock); return ret; @@ -921,9 +929,6 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct fimc_fmt *ffmt = NULL; int ret = 0; - fimc_md_graph_lock(ve); - mutex_lock(&fimc->lock); - if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, @@ -934,16 +939,18 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SOURCE); - if (!ffmt) { - ret = -EINVAL; - goto unlock; - } + if (!ffmt) + return -EINVAL; if (!fimc->vid_cap.user_subdev_api) { mf.width = pix->width; mf.height = pix->height; mf.code = ffmt->mbus_code; + + fimc_md_graph_lock(ve); fimc_pipeline_try_format(ctx, &mf, &ffmt, false); + fimc_md_graph_unlock(ve); + pix->width = mf.width; pix->height = mf.height; if (ffmt) @@ -955,9 +962,6 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, if (ffmt->flags & FMT_FLAGS_COMPRESSED) fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], pix->plane_fmt, ffmt->memplanes, true); -unlock: - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(ve); return ret; } @@ -1059,19 +1063,14 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, int ret; fimc_md_graph_lock(&fimc->vid_cap.ve); - mutex_lock(&fimc->lock); /* * The graph is walked within __fimc_capture_set_format() to set * the format at subdevs thus the graph mutex needs to be held at - * this point and acquired before the video mutex, to avoid AB-BA - * deadlock when fimc_md_link_notify() is called by other thread. - * Ideally the graph walking and setting format at the whole pipeline - * should be removed from this driver and handled in userspace only. + * this point. */ ret = __fimc_capture_set_format(fimc, f); fimc_md_graph_unlock(&fimc->vid_cap.ve); - mutex_unlock(&fimc->lock); return ret; } @@ -1790,12 +1789,6 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, ret = fimc_ctrls_create(ctx); if (ret) goto err_me_cleanup; - /* - * For proper order of acquiring/releasing the video - * and the graph mutex. - */ - v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT); - v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT); ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 61c0c83cc5b7..e3da4ffd7a5e 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -298,7 +298,6 @@ struct fimc_m2m_device { * @frame_count: the frame counter for statistics * @reqbufs_count: the number of buffers requested in REQBUFS ioctl * @input_index: input (camera sensor) index - * @refcnt: driver's private reference counter * @input: capture input type, grp_id of the attached subdev * @user_subdev_api: true if subdevs are not configured by the host driver * @inh_sensor_ctrls: a flag indicating v4l2 controls are inherited from @@ -323,7 +322,6 @@ struct fimc_vid_cap { unsigned int reqbufs_count; bool streaming; int input_index; - int refcnt; u32 input; bool user_subdev_api; bool inh_sensor_ctrls; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 64198b84f673..0f372bfffaf0 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -461,8 +461,6 @@ static int fimc_lite_open(struct file *file) struct media_entity *me = &fimc->ve.vdev.entity; int ret; - mutex_lock(&me->parent->graph_mutex); - mutex_lock(&fimc->lock); if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { ret = -EBUSY; @@ -482,11 +480,19 @@ static int fimc_lite_open(struct file *file) atomic_read(&fimc->out_path) != FIMC_IO_DMA) goto unlock; + mutex_lock(&me->parent->graph_mutex); + ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, me, true); + + /* Mark video pipeline ending at this video node as in use. */ + if (ret == 0) + me->use_count++; + + mutex_unlock(&me->parent->graph_mutex); + if (!ret) { fimc_lite_clear_event_counters(fimc); - fimc->ref_count++; goto unlock; } @@ -496,26 +502,28 @@ err_pm: clear_bit(ST_FLITE_IN_USE, &fimc->state); unlock: mutex_unlock(&fimc->lock); - mutex_unlock(&me->parent->graph_mutex); return ret; } static int fimc_lite_release(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); + struct media_entity *entity = &fimc->ve.vdev.entity; mutex_lock(&fimc->lock); if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { if (fimc->streaming) { - media_entity_pipeline_stop(&fimc->ve.vdev.entity); + media_entity_pipeline_stop(entity); fimc->streaming = false; } clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); - fimc->ref_count--; + mutex_lock(&entity->parent->graph_mutex); + entity->use_count--; + mutex_unlock(&entity->parent->graph_mutex); } vb2_fop_release(file); @@ -954,8 +962,6 @@ static int fimc_lite_link_setup(struct media_entity *entity, __func__, remote->entity->name, local->entity->name, flags, fimc->source_subdev_grp_id); - mutex_lock(&fimc->lock); - switch (local->index) { case FLITE_SD_PAD_SINK: if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) { @@ -997,7 +1003,6 @@ static int fimc_lite_link_setup(struct media_entity *entity, } mb(); - mutex_unlock(&fimc->lock); return ret; } diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index fa3886a297ba..25abba98d7e9 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -125,7 +125,6 @@ struct flite_buffer { * @active_buf_count: number of video buffers scheduled in hardware * @frame_count: the captured frames counter * @reqbufs_count: the number of buffers requested with REQBUFS ioctl - * @ref_count: driver's private reference counter */ struct fimc_lite { struct platform_device *pdev; @@ -163,7 +162,6 @@ struct fimc_lite { struct vb2_queue vb_queue; unsigned int frame_count; unsigned int reqbufs_count; - int ref_count; struct fimc_lite_events events; bool streaming; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 7a562d289977..1b4bb25d0a55 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1238,9 +1238,7 @@ static int fimc_md_link_notify(struct media_pad *source, struct fimc_dev *fimc = NULL; struct fimc_pipeline *pipeline; struct v4l2_subdev *sd; - struct mutex *lock; int i, ret = 0; - int ref_count; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return 0; @@ -1253,29 +1251,24 @@ static int fimc_md_link_notify(struct media_pad *source, if (WARN_ON(fimc_lite == NULL)) return 0; pipeline = &fimc_lite->pipeline; - lock = &fimc_lite->lock; break; case GRP_ID_FIMC: fimc = v4l2_get_subdevdata(sd); if (WARN_ON(fimc == NULL)) return 0; pipeline = &fimc->pipeline; - lock = &fimc->lock; break; default: return 0; } - mutex_lock(lock); - ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - if (ref_count > 0) { + if (sink->entity->use_count > 0) { ret = __fimc_pipeline_close(pipeline); } for (i = 0; i < IDX_MAX; i++) pipeline->subdevs[i] = NULL; - } else if (ref_count > 0) { + } else if (sink->entity->use_count > 0) { /* * Link activation. Enable power of pipeline elements only if * the pipeline is already in use, i.e. its video node is open. @@ -1285,7 +1278,6 @@ static int fimc_md_link_notify(struct media_pad *source, source->entity, true); } - mutex_unlock(lock); return ret ? -EPIPE : ret; } -- cgit v1.2.3 From 403dfbec45419c1838e0ea3be16625986ec17cfd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 31 May 2013 11:37:22 -0300 Subject: [media] exynos4-is: Use common exynos_media_pipeline data structure This enumeration is now private to exynos4-is and the exynos5 camera subsystem driver may have the subdevs handling designed differently. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 67 ++++++++------ drivers/media/platform/exynos4-is/fimc-core.h | 2 - drivers/media/platform/exynos4-is/fimc-lite.c | 29 +++--- drivers/media/platform/exynos4-is/fimc-lite.h | 2 - drivers/media/platform/exynos4-is/media-dev.c | 110 ++++++++++++++--------- drivers/media/platform/exynos4-is/media-dev.h | 38 ++++++++ include/media/s5p_fimc.h | 53 ++++++----- 7 files changed, 187 insertions(+), 114 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index b2f9581f1a8a..33c6a2f0ad74 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -120,8 +120,7 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 0); + return fimc_pipeline_call(&cap->ve, set_stream, 0); else return 0; } @@ -179,8 +178,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { - struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe); + struct v4l2_subdev *csis = p->subdevs[IDX_CSIS]; struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; struct timeval *tv; @@ -288,8 +288,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) fimc_activate_capture(ctx); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + return fimc_pipeline_call(&vid_cap->ve, set_stream, 1); } return 0; @@ -313,7 +312,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc) int ret = fimc_stop_capture(fimc, suspend); if (ret) return ret; - return fimc_pipeline_call(fimc, close, &fimc->pipeline); + return fimc_pipeline_call(&fimc->vid_cap.ve, close); } static void buffer_queue(struct vb2_buffer *vb); @@ -330,8 +329,7 @@ int fimc_capture_resume(struct fimc_dev *fimc) INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); vid_cap->buf_index = 0; - fimc_pipeline_call(fimc, open, &fimc->pipeline, - &ve->vdev.entity, false); + fimc_pipeline_call(ve, open, &ve->vdev.entity, false); fimc_capture_hw_init(fimc); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); @@ -455,7 +453,7 @@ static void buffer_queue(struct vb2_buffer *vb) if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) return; - ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); + ret = fimc_pipeline_call(ve, set_stream, 1); if (ret < 0) v4l2_err(&ve->vdev, "stream on failed: %d\n", ret); return; @@ -503,8 +501,8 @@ static int fimc_capture_open(struct file *file) if (v4l2_fh_is_singular_file(file)) { fimc_md_graph_lock(ve); - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - &fimc->vid_cap.ve.vdev.entity, true); + ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true); + if (ret == 0) ret = fimc_capture_set_default_format(fimc); @@ -555,8 +553,7 @@ static int fimc_capture_release(struct file *file) if (close) { clear_bit(ST_CAPT_BUSY, &fimc->state); - fimc_stop_capture(fimc, false); - fimc_pipeline_call(fimc, close, &fimc->pipeline); + fimc_pipeline_call(&vc->ve, close); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); fimc_md_graph_lock(&vc->ve); @@ -786,7 +783,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, bool set) { struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe); + struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR]; struct v4l2_subdev_format sfmt; struct v4l2_mbus_framefmt *mf = &sfmt.format; struct media_entity *me; @@ -926,6 +924,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct exynos_video_entity *ve = &fimc->vid_cap.ve; struct v4l2_mbus_framefmt mf; + struct v4l2_subdev *sensor; struct fimc_fmt *ffmt = NULL; int ret = 0; @@ -959,9 +958,18 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); - if (ffmt->flags & FMT_FLAGS_COMPRESSED) - fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], - pix->plane_fmt, ffmt->memplanes, true); + if (ffmt->flags & FMT_FLAGS_COMPRESSED) { + fimc_md_graph_lock(ve); + + sensor = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR); + if (sensor) + fimc_get_sensor_frame_desc(sensor, pix->plane_fmt, + ffmt->memplanes, true); + else + ret = -EPIPE; + + fimc_md_graph_unlock(ve); + } return ret; } @@ -986,6 +994,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt; + struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe); struct fimc_frame *ff = &ctx->d_frame; struct fimc_fmt *s_fmt = NULL; int ret, i; @@ -1027,7 +1036,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { - ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + ret = fimc_get_sensor_frame_desc(p->subdevs[IDX_SENSOR], pix->plane_fmt, ff->fmt->memplanes, true); if (ret < 0) @@ -1078,14 +1087,20 @@ static int fimc_cap_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct fimc_dev *fimc = video_drvdata(file); - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + struct exynos_video_entity *ve = &fimc->vid_cap.ve; + struct v4l2_subdev *sd; if (i->index != 0) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; + fimc_md_graph_lock(ve); + sd = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR); + fimc_md_graph_unlock(ve); + if (sd) strlcpy(i->name, sd->name, sizeof(i->name)); + return 0; } @@ -1111,6 +1126,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) struct v4l2_subdev_format sink_fmt, src_fmt; struct fimc_vid_cap *vc = &fimc->vid_cap; struct v4l2_subdev *sd = &vc->subdev; + struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe); struct media_pad *sink_pad, *src_pad; int i, ret; @@ -1164,7 +1180,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) src_fmt.format.code != sink_fmt.format.code) return -EPIPE; - if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + if (sd == p->subdevs[IDX_SENSOR] && fimc_user_defined_mbus_fmt(src_fmt.format.code)) { struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; struct fimc_frame *frame = &vc->ctx->d_frame; @@ -1188,7 +1204,6 @@ static int fimc_cap_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); - struct fimc_pipeline *p = &fimc->pipeline; struct fimc_vid_cap *vc = &fimc->vid_cap; struct media_entity *entity = &vc->ve.vdev.entity; struct fimc_source_info *si = NULL; @@ -1198,11 +1213,11 @@ static int fimc_cap_streamon(struct file *file, void *priv, if (fimc_capture_active(fimc)) return -EBUSY; - ret = media_entity_pipeline_start(entity, p->m_pipeline); + ret = media_entity_pipeline_start(entity, &vc->ve.pipe->mp); if (ret < 0) return ret; - sd = p->subdevs[IDX_SENSOR]; + sd = __fimc_md_get_subdev(vc->ve.pipe, IDX_SENSOR); if (sd) si = v4l2_get_subdev_hostdata(sd); @@ -1821,12 +1836,12 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) if (ret) return ret; - fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + fimc->vid_cap.ve.pipe = v4l2_get_subdev_hostdata(sd); ret = fimc_register_capture_device(fimc, sd->v4l2_dev); if (ret) { fimc_unregister_m2m_device(fimc); - fimc->pipeline_ops = NULL; + fimc->vid_cap.ve.pipe = NULL; } return ret; @@ -1847,7 +1862,7 @@ static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd) video_unregister_device(vdev); media_entity_cleanup(&vdev->entity); fimc_ctrls_delete(fimc->vid_cap.ctx); - fimc->pipeline_ops = NULL; + fimc->vid_cap.ve.pipe = NULL; } kfree(fimc->vid_cap.ctx); fimc->vid_cap.ctx = NULL; diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index e3da4ffd7a5e..c48a79254d83 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -435,8 +435,6 @@ struct fimc_dev { struct fimc_vid_cap vid_cap; unsigned long state; struct vb2_alloc_ctx *alloc_ctx; - struct fimc_pipeline pipeline; - const struct fimc_pipeline_ops *pipeline_ops; }; /** diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 0f372bfffaf0..24e2a0f8797a 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -210,7 +210,7 @@ static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend) if (!streaming) return 0; - return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); + return fimc_pipeline_call(&fimc->ve, set_stream, 0); } static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend) @@ -324,8 +324,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) flite_hw_capture_start(fimc); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + fimc_pipeline_call(&fimc->ve, set_stream, 1); } if (debug > 0) flite_hw_dump_regs(fimc, __func__); @@ -429,8 +428,7 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + fimc_pipeline_call(&fimc->ve, set_stream, 1); return; } spin_unlock_irqrestore(&fimc->slock, flags); @@ -482,8 +480,7 @@ static int fimc_lite_open(struct file *file) mutex_lock(&me->parent->graph_mutex); - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - me, true); + ret = fimc_pipeline_call(&fimc->ve, open, me, true); /* Mark video pipeline ending at this video node as in use. */ if (ret == 0) @@ -518,9 +515,10 @@ static int fimc_lite_release(struct file *file) media_entity_pipeline_stop(entity); fimc->streaming = false; } - clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); - fimc_pipeline_call(fimc, close, &fimc->pipeline); + fimc_pipeline_call(&fimc->ve, close); + clear_bit(ST_FLITE_IN_USE, &fimc->state); + mutex_lock(&entity->parent->graph_mutex); entity->use_count--; mutex_unlock(&entity->parent->graph_mutex); @@ -801,13 +799,12 @@ static int fimc_lite_streamon(struct file *file, void *priv, { struct fimc_lite *fimc = video_drvdata(file); struct media_entity *entity = &fimc->ve.vdev.entity; - struct fimc_pipeline *p = &fimc->pipeline; int ret; if (fimc_lite_active(fimc)) return -EBUSY; - ret = media_entity_pipeline_start(entity, p->m_pipeline); + ret = media_entity_pipeline_start(entity, &fimc->ve.pipe->mp); if (ret < 0) return ret; @@ -1282,12 +1279,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) return ret; video_set_drvdata(vfd, fimc); - fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + fimc->ve.pipe = v4l2_get_subdev_hostdata(sd); ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret < 0) { media_entity_cleanup(&vfd->entity); - fimc->pipeline_ops = NULL; + fimc->ve.pipe = NULL; return ret; } @@ -1306,7 +1303,7 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd) if (video_is_registered(&fimc->ve.vdev)) { video_unregister_device(&fimc->ve.vdev); media_entity_cleanup(&fimc->ve.vdev.entity); - fimc->pipeline_ops = NULL; + fimc->ve.pipe = NULL; } } @@ -1552,7 +1549,7 @@ static int fimc_lite_resume(struct device *dev) return 0; INIT_LIST_HEAD(&fimc->active_buf_q); - fimc_pipeline_call(fimc, open, &fimc->pipeline, + fimc_pipeline_call(&fimc->ve, open, &fimc->ve.vdev.entity, false); fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); @@ -1579,7 +1576,7 @@ static int fimc_lite_suspend(struct device *dev) if (ret < 0 || !fimc_lite_active(fimc)) return ret; - return fimc_pipeline_call(fimc, close, &fimc->pipeline); + return fimc_pipeline_call(&fimc->ve, close); } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 25abba98d7e9..c7aa08477830 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -140,8 +140,6 @@ struct fimc_lite { struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *test_pattern; int index; - struct fimc_pipeline pipeline; - const struct fimc_pipeline_ops *pipeline_ops; struct mutex lock; spinlock_t slock; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 1b4bb25d0a55..2020e44f63b1 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -46,7 +46,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, * Caller holds the graph mutex. */ static void fimc_pipeline_prepare(struct fimc_pipeline *p, - struct media_entity *me) + struct media_entity *me) { struct v4l2_subdev *sd; int i; @@ -168,10 +168,11 @@ error: * * Called with the graph mutex held. */ -static int __fimc_pipeline_open(struct fimc_pipeline *p, +static int __fimc_pipeline_open(struct exynos_media_pipeline *ep, struct media_entity *me, bool prepare) { struct fimc_md *fmd = entity_to_fimc_mdev(me); + struct fimc_pipeline *p = to_fimc_pipeline(ep); struct v4l2_subdev *sd; int ret; @@ -214,8 +215,9 @@ err_wbclk: * * Disable power of all subdevs and turn the external sensor clock off. */ -static int __fimc_pipeline_close(struct fimc_pipeline *p) +static int __fimc_pipeline_close(struct exynos_media_pipeline *ep) { + struct fimc_pipeline *p = to_fimc_pipeline(ep); struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; struct fimc_md *fmd; int ret = 0; @@ -242,12 +244,13 @@ static int __fimc_pipeline_close(struct fimc_pipeline *p) * @pipeline: video pipeline structure * @on: passed as the s_stream() callback argument */ -static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) +static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on) { static const u8 seq[2][IDX_MAX] = { { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE }, { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, }; + struct fimc_pipeline *p = to_fimc_pipeline(ep); int i, ret = 0; if (p->subdevs[IDX_SENSOR] == NULL) @@ -271,12 +274,38 @@ error: } /* Media pipeline operations for the FIMC/FIMC-LITE video device driver */ -static const struct fimc_pipeline_ops fimc_pipeline_ops = { +static const struct exynos_media_pipeline_ops fimc_pipeline_ops = { .open = __fimc_pipeline_open, .close = __fimc_pipeline_close, .set_stream = __fimc_pipeline_s_stream, }; +static struct exynos_media_pipeline *fimc_md_pipeline_create( + struct fimc_md *fmd) +{ + struct fimc_pipeline *p; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return NULL; + + list_add_tail(&p->list, &fmd->pipelines); + + p->ep.ops = &fimc_pipeline_ops; + return &p->ep; +} + +static void fimc_md_pipelines_free(struct fimc_md *fmd) +{ + while (!list_empty(&fmd->pipelines)) { + struct fimc_pipeline *p; + + p = list_entry(fmd->pipelines.next, typeof(*p), list); + list_del(&p->list); + kfree(p); + } +} + /* * Sensor subdevice helper functions */ @@ -592,6 +621,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd, struct fimc_lite *fimc_lite) { struct v4l2_subdev *sd; + struct exynos_media_pipeline *ep; int ret; if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS || @@ -600,7 +630,12 @@ static int register_fimc_lite_entity(struct fimc_md *fmd, sd = &fimc_lite->subdev; sd->grp_id = GRP_ID_FLITE; - v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); + + ep = fimc_md_pipeline_create(fmd); + if (!ep) + return -ENOMEM; + + v4l2_set_subdev_hostdata(sd, ep); ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (!ret) @@ -614,6 +649,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd, static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) { struct v4l2_subdev *sd; + struct exynos_media_pipeline *ep; int ret; if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id])) @@ -621,7 +657,12 @@ static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) sd = &fimc->vid_cap.subdev; sd->grp_id = GRP_ID_FIMC; - v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); + + ep = fimc_md_pipeline_create(fmd); + if (!ep) + return -ENOMEM; + + v4l2_set_subdev_hostdata(sd, ep); ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (!ret) { @@ -797,17 +838,19 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) int i; for (i = 0; i < FIMC_MAX_DEVS; i++) { - if (fmd->fimc[i] == NULL) + struct fimc_dev *dev = fmd->fimc[i]; + if (dev == NULL) continue; - v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev); - fmd->fimc[i]->pipeline_ops = NULL; + v4l2_device_unregister_subdev(&dev->vid_cap.subdev); + dev->vid_cap.ve.pipe = NULL; fmd->fimc[i] = NULL; } for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { - if (fmd->fimc_lite[i] == NULL) + struct fimc_lite *dev = fmd->fimc_lite[i]; + if (dev == NULL) continue; - v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev); - fmd->fimc_lite[i]->pipeline_ops = NULL; + v4l2_device_unregister_subdev(&dev->subdev); + dev->ve.pipe = NULL; fmd->fimc_lite[i] = NULL; } for (i = 0; i < CSIS_MAX_ENTITIES; i++) { @@ -1234,38 +1277,22 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { - struct fimc_lite *fimc_lite = NULL; - struct fimc_dev *fimc = NULL; + struct exynos_video_entity *ve; + struct video_device *vdev; struct fimc_pipeline *pipeline; - struct v4l2_subdev *sd; int i, ret = 0; - if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE_V4L) return 0; - sd = media_entity_to_v4l2_subdev(sink->entity); - - switch (sd->grp_id) { - case GRP_ID_FLITE: - fimc_lite = v4l2_get_subdevdata(sd); - if (WARN_ON(fimc_lite == NULL)) - return 0; - pipeline = &fimc_lite->pipeline; - break; - case GRP_ID_FIMC: - fimc = v4l2_get_subdevdata(sd); - if (WARN_ON(fimc == NULL)) - return 0; - pipeline = &fimc->pipeline; - break; - default: - return 0; - } + vdev = media_entity_to_video_device(sink->entity); + ve = vdev_to_exynos_video_entity(vdev); + pipeline = to_fimc_pipeline(ve->pipe); + + if (!(flags & MEDIA_LNK_FL_ENABLED) && pipeline->subdevs[IDX_SENSOR]) { + if (sink->entity->use_count > 0) + ret = __fimc_pipeline_close(ve->pipe); - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - if (sink->entity->use_count > 0) { - ret = __fimc_pipeline_close(pipeline); - } for (i = 0; i < IDX_MAX; i++) pipeline->subdevs[i] = NULL; } else if (sink->entity->use_count > 0) { @@ -1274,8 +1301,7 @@ static int fimc_md_link_notify(struct media_pad *source, * the pipeline is already in use, i.e. its video node is open. * Recreate the controls destroyed during the link deactivation. */ - ret = __fimc_pipeline_open(pipeline, - source->entity, true); + ret = __fimc_pipeline_open(ve->pipe, sink->entity, true); } return ret ? -EPIPE : ret; @@ -1358,6 +1384,7 @@ static int fimc_md_probe(struct platform_device *pdev) spin_lock_init(&fmd->slock); fmd->pdev = pdev; + INIT_LIST_HEAD(&fmd->pipelines); strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", sizeof(fmd->media_dev.model)); @@ -1445,6 +1472,7 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); fimc_md_unregister_entities(fmd); + fimc_md_pipelines_free(fmd); media_device_unregister(&fmd->media_dev); fimc_md_put_clocks(fmd); return 0; diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 3e9680c9de8b..a704eea2cfbd 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "fimc-core.h" #include "fimc-lite.h" @@ -40,6 +41,29 @@ enum { FIMC_MAX_WBCLKS }; +enum fimc_subdev_index { + IDX_SENSOR, + IDX_CSIS, + IDX_FLITE, + IDX_IS_ISP, + IDX_FIMC, + IDX_MAX, +}; + +/* + * This structure represents a chain of media entities, including a data + * source entity (e.g. an image sensor subdevice), a data capture entity + * - a video capture device node and any remaining entities. + */ +struct fimc_pipeline { + struct exynos_media_pipeline ep; + struct list_head list; + struct media_entity *vdev_entity; + struct v4l2_subdev *subdevs[IDX_MAX]; +}; + +#define to_fimc_pipeline(_ep) container_of(_ep, struct fimc_pipeline, ep) + struct fimc_csis_info { struct v4l2_subdev *sd; int id; @@ -104,7 +128,9 @@ struct fimc_md { struct pinctrl_state *state_idle; } pinctl; bool user_subdev_api; + spinlock_t slock; + struct list_head pipelines; }; #define is_subdev_pad(pad) (pad == NULL || \ @@ -149,4 +175,16 @@ static inline bool fimc_md_is_isp_available(struct device_node *node) #define fimc_md_is_isp_available(node) (false) #endif /* CONFIG_OF */ +static inline struct v4l2_subdev *__fimc_md_get_subdev( + struct exynos_media_pipeline *ep, + unsigned int index) +{ + struct fimc_pipeline *p = to_fimc_pipeline(ep); + + if (!p || index >= IDX_MAX) + return NULL; + else + return p->subdevs[index]; +} + #endif diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index f5313b402eb7..0afadb663bbd 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -141,41 +141,40 @@ struct fimc_fmt { #define FMT_FLAGS_YUV (1 << 7) }; -enum fimc_subdev_index { - IDX_SENSOR, - IDX_CSIS, - IDX_FLITE, - IDX_IS_ISP, - IDX_FIMC, - IDX_MAX, -}; - -struct media_pipeline; -struct v4l2_subdev; +struct exynos_media_pipeline; -struct fimc_pipeline { - struct v4l2_subdev *subdevs[IDX_MAX]; - struct media_pipeline *m_pipeline; +/* + * Media pipeline operations to be called from within a video node, i.e. the + * last entity within the pipeline. Implemented by related media device driver. + */ +struct exynos_media_pipeline_ops { + int (*prepare)(struct exynos_media_pipeline *p, + struct media_entity *me); + int (*unprepare)(struct exynos_media_pipeline *p); + int (*open)(struct exynos_media_pipeline *p, struct media_entity *me, + bool resume); + int (*close)(struct exynos_media_pipeline *p); + int (*set_stream)(struct exynos_media_pipeline *p, bool state); }; struct exynos_video_entity { struct video_device vdev; + struct exynos_media_pipeline *pipe; }; -/* - * Media pipeline operations to be called from within the fimc(-lite) - * video node when it is the last entity of the pipeline. Implemented - * by corresponding media device driver. - */ -struct fimc_pipeline_ops { - int (*open)(struct fimc_pipeline *p, struct media_entity *me, - bool resume); - int (*close)(struct fimc_pipeline *p); - int (*set_stream)(struct fimc_pipeline *p, bool state); +struct exynos_media_pipeline { + struct media_pipeline mp; + const struct exynos_media_pipeline_ops *ops; }; -#define fimc_pipeline_call(f, op, p, args...) \ - (!(f) ? -ENODEV : (((f)->pipeline_ops && (f)->pipeline_ops->op) ? \ - (f)->pipeline_ops->op((p), ##args) : -ENOIOCTLCMD)) +static inline struct exynos_video_entity *vdev_to_exynos_video_entity( + struct video_device *vdev) +{ + return container_of(vdev, struct exynos_video_entity, vdev); +} + +#define fimc_pipeline_call(ent, op, args...) \ + (!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \ + (ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD)) \ #endif /* S5P_FIMC_H_ */ -- cgit v1.2.3 From 47d1f33ff43e3d4f74fff1892d44d1de34a80be2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 11 Jun 2013 10:44:38 -0300 Subject: [media] exynos4-is: Drop drvdata handling in fimc-lite for non-dt platforms The FIMC-LITE IP block is available only on platforms instantiated from device tree. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.c | 3 --- drivers/media/platform/exynos4-is/fimc-lite.h | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 3f76f8abc4b3..00c525c377d8 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1449,9 +1449,6 @@ static int fimc_lite_probe(struct platform_device *pdev) if (of_id) drv_data = (struct flite_drvdata *)of_id->data; fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); - } else { - drv_data = fimc_lite_get_drvdata(pdev); - fimc->index = pdev->id; } if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index c7aa08477830..4b1068425dad 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -56,9 +56,6 @@ struct flite_drvdata { unsigned short out_hor_offs_align; }; -#define fimc_lite_get_drvdata(_pdev) \ - ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data) - struct fimc_lite_events { unsigned int data_overflow; }; -- cgit v1.2.3 From 086eca2905d0d1ea6b5e22d62648c6b818c51846 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 14 Jun 2013 12:38:15 -0300 Subject: [media] exynos4-is: Add Exynos5250 SoC support to fimc-lite driver This patch adds support for the Exynos5250 SoC variant of the FIMC-LITE IP. A 'compatible' string is added for Exynos5250 compatible devices and the capture DMA handling is reworked to use the FLITE_REG_CIFCNTSEQ register, masking output DMA buffer address slots. The frame interrupt is enabled so there are now 2 interrupts per frame. This likely can be optimized in future by using any status registers that allow to figure out what the last and the currently written frame buffer is. It would also be more reliable in cases where there are high interrupt service latencies. Signed-off-by: Shaik Ameer Basha Signed-off-by: Arun Kumar K Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park --- .../devicetree/bindings/media/exynos-fimc-lite.txt | 6 ++- drivers/media/platform/exynos4-is/fimc-lite-reg.c | 53 ++++++++++++++++++++-- drivers/media/platform/exynos4-is/fimc-lite-reg.h | 10 +++- drivers/media/platform/exynos4-is/fimc-lite.c | 50 +++++++++++++++++--- drivers/media/platform/exynos4-is/fimc-lite.h | 22 ++++++++- 5 files changed, 125 insertions(+), 16 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt index de9f6b78ee51..0bf6fb7fbeab 100644 --- a/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt +++ b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt @@ -2,8 +2,10 @@ Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE) Required properties: -- compatible : should be "samsung,exynos4212-fimc-lite" for Exynos4212 and - Exynos4412 SoCs; +- compatible : should be one of: + "samsung,exynos4212-fimc-lite" for Exynos4212/4412 SoCs, + "samsung,exynos5250-fimc-lite" for Exynos5250 compatible + devices; - reg : physical base address and size of the device memory mapped registers; - interrupts : should contain FIMC-LITE interrupt; diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index eb4f7635f5e0..72a343e3b5e8 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -2,15 +2,16 @@ * Register interface file for EXYNOS FIMC-LITE (camera interface) driver * * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki + * Author: Sylwester Nawrocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include +#include #include +#include #include #include "fimc-lite-reg.h" @@ -68,7 +69,8 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev) if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | FLITE_REG_CIGCTRL_IRQ_LASTEN | - FLITE_REG_CIGCTRL_IRQ_STARTEN; + FLITE_REG_CIGCTRL_IRQ_STARTEN | + FLITE_REG_CIGCTRL_IRQ_ENDEN; } else { /* An output to the FIMC-IS */ intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | @@ -215,6 +217,18 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev, flite_hw_set_camera_port(dev, si->mux_id); } +static void flite_hw_set_pack12(struct fimc_lite *dev, int on) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); + + cfg &= ~FLITE_REG_CIODMAFMT_PACK12; + + if (on) + cfg |= FLITE_REG_CIODMAFMT_PACK12; + + writel(cfg, dev->regs + FLITE_REG_CIODMAFMT); +} + static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) { static const u32 pixcode[4][2] = { @@ -250,6 +264,38 @@ void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f) writel(cfg, dev->regs + FLITE_REG_CIOOFF); } +void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf) +{ + unsigned int index; + u32 cfg; + + if (dev->dd->max_dma_bufs == 1) + index = 0; + else + index = buf->index; + + if (index == 0) + writel(buf->paddr, dev->regs + FLITE_REG_CIOSA); + else + writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1)); + + cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ); + cfg |= BIT(index); + writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ); +} + +void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index) +{ + u32 cfg; + + if (dev->dd->max_dma_bufs == 1) + index = 0; + + cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ); + cfg &= ~BIT(index); + writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ); +} + /* Enable/disable output DMA, set output pixel size and offsets (composition) */ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, bool enable) @@ -267,6 +313,7 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, flite_hw_set_out_order(dev, f); flite_hw_set_dma_window(dev, f); + flite_hw_set_pack12(dev, 0); } void flite_hw_dump_regs(struct fimc_lite *dev, const char *label) diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 390383941c19..10a7d7bbcc27 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -120,6 +120,9 @@ /* b0: 1 - camera B, 0 - camera A */ #define FLITE_REG_CIGENERAL_CAM_B (1 << 0) +#define FLITE_REG_CIFCNTSEQ 0x100 +#define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x))) + /* ---------------------------------------------------------------------------- * Function declarations */ @@ -142,9 +145,12 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f); void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on); void flite_hw_dump_regs(struct fimc_lite *dev, const char *label); +void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf); +void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index); -static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr) +static inline void flite_hw_set_dma_buf_mask(struct fimc_lite *dev, u32 mask) { - writel(paddr, dev->regs + FLITE_REG_CIOSA); + writel(mask, dev->regs + FLITE_REG_CIFCNTSEQ); } + #endif /* FIMC_LITE_REG_H */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 00c525c377d8..07767c8b1c62 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -153,6 +153,7 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) flite_hw_set_camera_bus(fimc, si); flite_hw_set_source_format(fimc, &fimc->inp_frame); flite_hw_set_window_offset(fimc, &fimc->inp_frame); + flite_hw_set_dma_buf_mask(fimc, 0); flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output); flite_hw_set_interrupt_mask(fimc); flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); @@ -276,19 +277,23 @@ static irqreturn_t flite_irq_handler(int irq, void *priv) if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && test_bit(ST_FLITE_RUN, &fimc->state) && - !list_empty(&fimc->active_buf_q) && !list_empty(&fimc->pending_buf_q)) { + vbuf = fimc_lite_pending_queue_pop(fimc); + flite_hw_set_dma_buffer(fimc, vbuf); + fimc_lite_active_queue_add(fimc, vbuf); + } + + if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMEND) && + test_bit(ST_FLITE_RUN, &fimc->state) && + !list_empty(&fimc->active_buf_q)) { vbuf = fimc_lite_active_queue_pop(fimc); ktime_get_ts(&ts); tv = &vbuf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; + flite_hw_mask_dma_buffer(fimc, vbuf->index); vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); - - vbuf = fimc_lite_pending_queue_pop(fimc); - flite_hw_set_output_addr(fimc, vbuf->paddr); - fimc_lite_active_queue_add(fimc, vbuf); } if (test_bit(ST_FLITE_CONFIG, &fimc->state)) @@ -307,10 +312,16 @@ done: static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_lite *fimc = q->drv_priv; + unsigned long flags; int ret; + spin_lock_irqsave(&fimc->slock, flags); + + fimc->buf_index = 0; fimc->frame_count = 0; + spin_unlock_irqrestore(&fimc->slock, flags); + ret = fimc_lite_hw_init(fimc, false); if (ret) { fimc_lite_reinit(fimc, false); @@ -412,10 +423,14 @@ static void buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&fimc->slock, flags); buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + buf->index = fimc->buf_index++; + if (fimc->buf_index >= fimc->reqbufs_count) + fimc->buf_index = 0; + if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) && !test_bit(ST_FLITE_STREAM, &fimc->state) && list_empty(&fimc->active_buf_q)) { - flite_hw_set_output_addr(fimc, buf->paddr); + flite_hw_set_dma_buffer(fimc, buf); fimc_lite_active_queue_add(fimc, buf); } else { fimc_lite_pending_queue_add(fimc, buf); @@ -1451,8 +1466,12 @@ static int fimc_lite_probe(struct platform_device *pdev) fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); } - if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) + if (!drv_data || fimc->index >= drv_data->num_instances || + fimc->index < 0) { + dev_err(dev, "Wrong %s node alias\n", + dev->of_node->full_name); return -EINVAL; + } fimc->dd = drv_data; fimc->pdev = pdev; @@ -1609,6 +1628,19 @@ static struct flite_drvdata fimc_lite_drvdata_exynos4 = { .out_width_align = 8, .win_hor_offs_align = 2, .out_hor_offs_align = 8, + .max_dma_bufs = 1, + .num_instances = 2, +}; + +/* EXYNOS5250 */ +static struct flite_drvdata fimc_lite_drvdata_exynos5 = { + .max_width = 8192, + .max_height = 8192, + .out_width_align = 8, + .win_hor_offs_align = 2, + .out_hor_offs_align = 8, + .max_dma_bufs = 32, + .num_instances = 3, }; static const struct of_device_id flite_of_match[] = { @@ -1616,6 +1648,10 @@ static const struct of_device_id flite_of_match[] = { .compatible = "samsung,exynos4212-fimc-lite", .data = &fimc_lite_drvdata_exynos4, }, + { + .compatible = "samsung,exynos5250-fimc-lite", + .data = &fimc_lite_drvdata_exynos5, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, flite_of_match); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 4b1068425dad..c98f3da74870 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -27,7 +27,7 @@ #define FIMC_LITE_DRV_NAME "exynos-fimc-lite" #define FLITE_CLK_NAME "flite" -#define FIMC_LITE_MAX_DEVS 2 +#define FIMC_LITE_MAX_DEVS 3 #define FLITE_REQ_BUFS_MIN 2 /* Bit index definitions for struct fimc_lite::state */ @@ -48,12 +48,26 @@ enum { #define FLITE_SD_PAD_SOURCE_ISP 2 #define FLITE_SD_PADS_NUM 3 +/** + * struct flite_drvdata - FIMC-LITE IP variant data structure + * @max_width: maximum camera interface input width in pixels + * @max_height: maximum camera interface input height in pixels + * @out_width_align: minimum output width alignment in pixels + * @win_hor_offs_align: minimum camera interface crop window horizontal + * offset alignment in pixels + * @out_hor_offs_align: minimum output DMA compose rectangle horizontal + * offset alignment in pixels + * @max_dma_bufs: number of output DMA buffer start address registers + * @num_instances: total number of FIMC-LITE IP instances available + */ struct flite_drvdata { unsigned short max_width; unsigned short max_height; unsigned short out_width_align; unsigned short win_hor_offs_align; unsigned short out_hor_offs_align; + unsigned short max_dma_bufs; + unsigned short num_instances; }; struct fimc_lite_events { @@ -80,12 +94,14 @@ struct flite_frame { * struct flite_buffer - video buffer structure * @vb: vb2 buffer * @list: list head for the buffers queue - * @paddr: precalculated physical address + * @paddr: DMA buffer start address + * @index: DMA start address register's index */ struct flite_buffer { struct vb2_buffer vb; struct list_head list; dma_addr_t paddr; + unsigned short index; }; /** @@ -119,6 +135,7 @@ struct flite_buffer { * @pending_buf_q: pending buffers queue head * @active_buf_q: the queue head of buffers scheduled in hardware * @vb_queue: vb2 buffers queue + * @buf_index: helps to keep track of the DMA start address register index * @active_buf_count: number of video buffers scheduled in hardware * @frame_count: the captured frames counter * @reqbufs_count: the number of buffers requested with REQBUFS ioctl @@ -155,6 +172,7 @@ struct fimc_lite { struct list_head pending_buf_q; struct list_head active_buf_q; struct vb2_queue vb_queue; + unsigned short buf_index; unsigned int frame_count; unsigned int reqbufs_count; -- cgit v1.2.3 From a055d97037ad09ad9b87f6a6e74a65a44b942102 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 18 Jun 2013 08:00:42 -0300 Subject: [media] exynos4-is: Set valid initial format at FIMC-LITE Ensure the image resolution and crop rectangle on the FIMC-LITE.n subdevs and fimc-lite.n.capture video nodes is properly configured upon the driver's initialization. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.c | 23 ++++++++++++++++++++--- drivers/media/platform/exynos4-is/fimc-lite.h | 2 ++ 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform/exynos4-is/fimc-lite.h') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 993bd798f3d2..4fa2e05186bd 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1281,9 +1281,6 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) int ret; memset(vfd, 0, sizeof(*vfd)); - - fimc->inp_frame.fmt = &fimc_lite_formats[0]; - fimc->out_frame.fmt = &fimc_lite_formats[0]; atomic_set(&fimc->out_path, FIMC_IO_DMA); snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", @@ -1399,6 +1396,23 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = { .step = 1, }; +static void fimc_lite_set_default_config(struct fimc_lite *fimc) +{ + struct flite_frame *sink = &fimc->inp_frame; + struct flite_frame *source = &fimc->out_frame; + + sink->fmt = &fimc_lite_formats[0]; + sink->f_width = FLITE_DEFAULT_WIDTH; + sink->f_height = FLITE_DEFAULT_HEIGHT; + + sink->rect.width = FLITE_DEFAULT_WIDTH; + sink->rect.height = FLITE_DEFAULT_HEIGHT; + sink->rect.left = 0; + sink->rect.top = 0; + + *source = *sink; +} + static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) { struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler; @@ -1544,8 +1558,11 @@ static int fimc_lite_probe(struct platform_device *pdev) ret = PTR_ERR(fimc->alloc_ctx); goto err_pm; } + pm_runtime_put(dev); + fimc_lite_set_default_config(fimc); + dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", fimc->index); return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index c98f3da74870..7428b2d22b52 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -29,6 +29,8 @@ #define FLITE_CLK_NAME "flite" #define FIMC_LITE_MAX_DEVS 3 #define FLITE_REQ_BUFS_MIN 2 +#define FLITE_DEFAULT_WIDTH 640 +#define FLITE_DEFAULT_HEIGHT 480 /* Bit index definitions for struct fimc_lite::state */ enum { -- cgit v1.2.3