@@ -75,11 +75,9 @@ static int fimc_start_capture(struct fimc_dev *fimc)
static int fimc_stop_capture(struct fimc_dev *fimc)
{
- unsigned long flags;
- struct fimc_vid_cap *cap;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
struct fimc_vid_buffer *buf;
-
- cap = &fimc->vid_cap;
+ unsigned long flags;
if (!fimc_capture_active(fimc))
return 0;
@@ -93,11 +91,10 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
!test_bit(ST_CAPT_SHUT, &fimc->state),
FIMC_SHUTDOWN_TIMEOUT);
- v4l2_subdev_call(cap->sd, video, s_stream, 0);
-
spin_lock_irqsave(&fimc->slock, flags);
fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
- 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM);
+ 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM |
+ 1 << ST_CAPT_ISP_STREAM);
fimc->vid_cap.active_buf_cnt = 0;
@@ -113,9 +110,9 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
}
spin_unlock_irqrestore(&fimc->slock, flags);
-
dbg("state: 0x%lx", fimc->state);
- return 0;
+
+ return fimc_pipeline_s_stream(fimc, 0);
}
int fimc_capture_suspend(struct fimc_dev *fimc)
@@ -219,10 +216,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
static void buffer_queue(struct vb2_buffer *vb)
{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_buffer *buf
= container_of(vb, struct fimc_vid_buffer, vb);
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
unsigned long flags;
int min_bufs;
@@ -249,9 +246,14 @@ static void buffer_queue(struct vb2_buffer *vb)
min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;
if (vid_cap->active_buf_cnt >= min_bufs &&
- !test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+ !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
fimc_activate_capture(ctx);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+ fimc_pipeline_s_stream(fimc, 1);
+ return;
+ }
spin_unlock_irqrestore(&fimc->slock, flags);
}
@@ -314,15 +316,19 @@ static int fimc_capture_open(struct file *file)
if (fimc_m2m_active(fimc))
return -EBUSY;
- ret = pm_runtime_get_sync(&fimc->pdev->dev);
- if (ret < 0) {
- v4l2_fh_release(file);
- return ret;
- }
+ pm_runtime_get_sync(&fimc->pdev->dev);
- if (++fimc->vid_cap.refcnt == 1)
+ if (++fimc->vid_cap.refcnt == 1) {
+ ret = fimc_pipeline_initialize(fimc,
+ &fimc->vid_cap.vfd->entity, true);
+ if (ret < 0) {
+ pm_runtime_put_sync(&fimc->pdev->dev);
+ fimc->vid_cap.refcnt--;
+ v4l2_fh_release(file);
+ return ret;
+ }
ret = fimc_capture_ctrls_create(fimc);
-
+ }
return ret;
}
@@ -334,10 +340,10 @@ static int fimc_capture_close(struct file *file)
if (--fimc->vid_cap.refcnt == 0) {
fimc_stop_capture(fimc);
+ fimc_pipeline_shutdown(fimc);
fimc_ctrls_delete(fimc->vid_cap.ctx);
vb2_queue_release(&fimc->vid_cap.vbq);
}
-
pm_runtime_put_sync(&fimc->pdev->dev);
return v4l2_fh_release(file);
}
@@ -398,39 +404,69 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
return 0;
}
-/* Synchronize formats of the camera interface input and attached sensor. */
-static int sync_capture_fmt(struct fimc_ctx *ctx)
+/**
+ * fimc_pipeline_try_or_set_fmt - negotiate and/or set formats at pipeline
+ * elements
+ * @ctx: FIMC capture context
+ * @ff: pixel format to verify (width/height/fmt)
+ * @mfmt: if NULL format is only tried on subdevs, if not NULL format
+ * will be set on subdevs and returned in @mfmt
+ */
+static int fimc_pipeline_try_or_set_fmt(struct fimc_ctx *ctx,
+ struct fimc_frame *ff,
+ struct v4l2_mbus_framefmt *mfmt)
{
- struct fimc_frame *frame = &ctx->s_frame;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
- int ret;
-
- fmt->width = ctx->d_frame.o_width;
- fmt->height = ctx->d_frame.o_height;
+ struct v4l2_subdev *sd = fimc->pipeline.sensor;
+ struct v4l2_subdev *csis = fimc->pipeline.csis;
+ struct v4l2_subdev_format sfmt;
+ struct v4l2_mbus_framefmt *mf = &sfmt.format;
+ struct fimc_fmt *ffmt;
+ int ret, i = 0;
+
+ if (!sd)
+ return -ENXIO;
- ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
- if (ret == -ENOIOCTLCMD) {
- err("s_mbus_fmt failed");
- return ret;
- }
- dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+ /* Configure pipeline formats only for sensors without a device node. */
+ if (subdev_has_devnode(sd))
+ return 0;
- frame->fmt = fimc_find_format(NULL, fmt, FMT_FLAGS_CAM, -1);
- if (!frame->fmt) {
- err("fimc source format not found\n");
- return -EINVAL;
+ memset(&sfmt, 0, sizeof(sfmt));
+ mf->width = ff->width;
+ mf->height = ff->height;
+ mf->code = -1;
+
+ dbg("code: 0x%x. %dx%d, dst: %dx%d", mf->code, mf->width, mf->height,
+ ff->width, ff->height);
+
+ sfmt.which = mfmt ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
+ while (ff->fmt->mbus_code != mf->code) {
+ if (mf->code != -1) {
+ ffmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, i++);
+ if(!ffmt)
+ return -EINVAL;
+ } else {
+ ffmt = ff->fmt;
+ }
+ mf->code = ffmt->mbus_code;
+ if (csis) {
+ ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
+ if (mf->code != ffmt->mbus_code ||
+ mf->width != ff->width ||
+ mf->width != ff->width)
+ continue;
+ }
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
+ if (ret)
+ return ret;
+ if (mf->code == ffmt->mbus_code &&
+ mf->width == ff->width &&
+ mf->width == ff->width)
+ break;
}
-
- frame->f_width = fmt->width;
- frame->f_height = fmt->height;
- frame->width = fmt->width;
- frame->height = fmt->height;
- frame->o_width = fmt->width;
- frame->o_height = fmt->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
-
+ dbg("code: 0x%x, %dx%d", mf->code, mf->width, mf->height);
+ if (mfmt)
+ *mfmt = *mf;
return 0;
}
@@ -460,6 +496,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
struct v4l2_pix_format_mplane *pix;
struct fimc_frame *frame;
int ret;
@@ -488,20 +525,23 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
(pix->width * pix->height * frame->fmt->depth[i]) >> 3;
}
- /* Output DMA frame pixel size and offsets. */
- frame->f_width = pix->plane_fmt[0].bytesperline * 8
- / frame->fmt->depth[0];
- frame->f_height = pix->height;
- frame->width = pix->width;
- frame->height = pix->height;
- frame->o_width = pix->width;
- frame->o_height = pix->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
-
- ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+ fimc_fill_frame(frame, f);
+ ctx->state |= FIMC_DST_FMT;
- ret = sync_capture_fmt(ctx);
+ fimc_md_graph_lock(fimc);
+ ret = fimc_pipeline_try_or_set_fmt(ctx, frame, mf);
+ fimc_md_graph_unlock(fimc);
+ if (!ret) {
+ frame = &ctx->s_frame;
+ frame->f_width = mf->width;
+ frame->f_height = mf->height;
+ frame->o_width = mf->width;
+ frame->o_height = mf->height;
+ frame->width = mf->width;
+ frame->height = mf->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+ }
return ret;
}
@@ -509,12 +549,14 @@ 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.sensor;
if (i->index != 0)
return -EINVAL;
-
i->type = V4L2_INPUT_TYPE_CAMERA;
+ if (sd)
+ strlcpy(i->name, sd->name, sizeof(i->name));
return 0;
}
@@ -534,14 +576,16 @@ static int fimc_cap_streamon(struct file *file, void *priv,
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_pipeline *p = &fimc->pipeline;
- if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+ if (fimc_capture_active(fimc))
return -EBUSY;
if (!(ctx->state & FIMC_DST_FMT)) {
v4l2_err(fimc->vid_cap.vfd, "Format is not set\n");
return -EINVAL;
}
+ media_entity_pipeline_start(&p->sensor->entity, p->pipe);
return vb2_streamon(&fimc->vid_cap.vbq, type);
}
@@ -550,8 +594,13 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_dev *fimc = video_drvdata(file);
+ struct v4l2_subdev *sd = fimc->pipeline.sensor;
+ int ret;
- return vb2_streamoff(&fimc->vid_cap.vbq, type);
+ ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
+ if (ret == 0)
+ media_entity_pipeline_stop(&sd->entity);
+ return ret;
}
static int fimc_cap_reqbufs(struct file *file, void *priv,
@@ -657,7 +706,6 @@ static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
return 0;
}
-
static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_querycap = fimc_vidioc_querycap_capture,
@@ -763,8 +811,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
vid_cap->active_buf_cnt = 0;
vid_cap->reqbufs_count = 0;
vid_cap->refcnt = 0;
- /* Default color format for image sensor */
- vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
INIT_LIST_HEAD(&vid_cap->pending_buf_q);
INIT_LIST_HEAD(&vid_cap->active_buf_q);
@@ -897,6 +897,21 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
return 0;
}
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+
+ frame->f_width = pixm->plane_fmt[0].bytesperline * 8 /
+ frame->fmt->depth[0];
+ frame->f_height = pixm->height;
+ frame->width = pixm->width;
+ frame->height = pixm->height;
+ frame->o_width = pixm->width;
+ frame->o_height = pixm->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+}
+
static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
@@ -1063,15 +1078,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
(pix->width * pix->height * frame->fmt->depth[i]) / 8;
}
- frame->f_width = pix->plane_fmt[0].bytesperline * 8 /
- frame->fmt->depth[0];
- frame->f_height = pix->height;
- frame->width = pix->width;
- frame->height = pix->height;
- frame->o_width = pix->width;
- frame->o_height = pix->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
+ fimc_fill_frame(frame, f);
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
@@ -1578,7 +1585,6 @@ static int fimc_probe(struct platform_device *pdev)
init_waitqueue_head(&fimc->irq_queue);
spin_lock_init(&fimc->slock);
-
mutex_init(&fimc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -43,6 +43,7 @@
#define SCALER_MAX_HRATIO 64
#define SCALER_MAX_VRATIO 64
#define DMA_MIN_SIZE 8
+#define FIMC_CAMIF_MAX_HEIGHT 0x2000
/* indices to the clocks array */
enum {
@@ -61,6 +62,7 @@ enum fimc_dev_flags {
ST_CAPT_PEND,
ST_CAPT_RUN,
ST_CAPT_STREAM,
+ ST_CAPT_ISP_STREAM,
ST_CAPT_SHUT,
ST_CAPT_INUSE,
ST_CAPT_APPLY_CFG,
@@ -293,7 +295,6 @@ struct fimc_m2m_device {
* struct fimc_vid_cap - camera capture device information
* @ctx: hardware context data
* @vfd: video device node for camera capture mode
- * @sd: pointer to camera sensor subdevice currently in use
* @vd_pad: fimc video capture node pad
* @fmt: Media Bus format configured at selected image sensor
* @pending_buf_q: the pending buffer queue head
@@ -311,9 +312,8 @@ struct fimc_vid_cap {
struct fimc_ctx *ctx;
struct vb2_alloc_ctx *alloc_ctx;
struct video_device *vfd;
- struct v4l2_subdev *sd;;
struct media_pad vd_pad;
- struct v4l2_mbus_framefmt fmt;
+ struct v4l2_mbus_framefmt mf;
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct vb2_queue vbq;
@@ -661,6 +661,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
struct fimc_frame *frame, struct fimc_addr *paddr);
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
void fimc_set_yuv_order(struct fimc_ctx *ctx);
+void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
int fimc_register_m2m_device(struct fimc_dev *fimc,
struct v4l2_device *v4l2_dev);
@@ -572,7 +572,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
- if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) {
+ if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
cfg = pix_desc[i].cisrcfmt;
bus_width = pix_desc[i].bus_width;
break;
@@ -582,7 +582,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
if (i == ARRAY_SIZE(pix_desc)) {
v4l2_err(fimc->vid_cap.vfd,
"Camera color format not supported: %d\n",
- fimc->vid_cap.fmt.code);
+ fimc->vid_cap.mf.code);
return -EINVAL;
}
@@ -642,12 +642,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
- if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+ if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) {
tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
} else {
v4l2_err(fimc->vid_cap.vfd,
"Not supported camera pixel format: %d",
- vid_cap->fmt.code);
+ vid_cap->mf.code);
return -EINVAL;
}
tmp |= (cam->csi_data_align == 32) << 8;