]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/media/platform/s5p-fimc/fimc-capture.c
Merge remote-tracking branch 'linus/master' into staging/for_v3.8
[karo-tx-linux.git] / drivers / media / platform / s5p-fimc / fimc-capture.c
index dded988152206e779c3f49844d5ade4a09f14663..0d0aca5008764048d262bd86bc584894289dbb1c 100644 (file)
@@ -177,7 +177,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_frame *f = &cap->ctx->d_frame;
        struct fimc_vid_buffer *v_buf;
        struct timeval *tv;
        struct timespec ts;
@@ -216,6 +218,25 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
                if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
                        cap->buf_index = 0;
        }
+       /*
+        * Set up a buffer at MIPI-CSIS if current image format
+        * requires the frame embedded data capture.
+        */
+       if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) {
+               unsigned int plane = ffs(f->fmt->mdataplanes) - 1;
+               unsigned int size = f->payload[plane];
+               s32 index = fimc_hw_get_frame_index(fimc);
+               void *vaddr;
+
+               list_for_each_entry(v_buf, &cap->active_buf_q, list) {
+                       if (v_buf->index != index)
+                               continue;
+                       vaddr = vb2_plane_vaddr(&v_buf->vb, plane);
+                       v4l2_subdev_call(csis, video, s_rx_buffer,
+                                        vaddr, &size);
+                       break;
+               }
+       }
 
        if (cap->active_buf_cnt == 0) {
                if (deq_buf)
@@ -351,6 +372,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
                unsigned int size = (wh * fmt->depth[i]) / 8;
                if (pixm)
                        sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+               else if (fimc_fmt_is_user_defined(fmt->color))
+                       sizes[i] = frame->payload[i];
                else
                        sizes[i] = max_t(u32, size, frame->payload[i]);
 
@@ -611,10 +634,10 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
        u32 mask = FMT_FLAGS_CAM;
        struct fimc_fmt *ffmt;
 
-       /* Color conversion from/to JPEG is not supported */
+       /* Conversion from/to JPEG or User Defined format is not supported */
        if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&
-           fimc_fmt_is_jpeg(ctx->s_frame.fmt->color))
-               *code = V4L2_MBUS_FMT_JPEG_1X8;
+           fimc_fmt_is_user_defined(ctx->s_frame.fmt->color))
+               *code = ctx->s_frame.fmt->mbus_code;
 
        if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
                mask |= FMT_FLAGS_M2M;
@@ -628,18 +651,19 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
                *fourcc = ffmt->fourcc;
 
        if (pad == FIMC_SD_PAD_SINK) {
-               max_w = fimc_fmt_is_jpeg(ffmt->color) ?
+               max_w = fimc_fmt_is_user_defined(ffmt->color) ?
                        pl->scaler_dis_w : pl->scaler_en_w;
                /* Apply the camera input interface pixel constraints */
                v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,
                                      height, max_t(u32, *height, 32),
                                      FIMC_CAMIF_MAX_HEIGHT,
-                                     fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1,
+                                     fimc_fmt_is_user_defined(ffmt->color) ?
+                                     3 : 1,
                                      0);
                return ffmt;
        }
        /* Can't scale or crop in transparent (JPEG) transfer mode */
-       if (fimc_fmt_is_jpeg(ffmt->color)) {
+       if (fimc_fmt_is_user_defined(ffmt->color)) {
                *width  = ctx->s_frame.f_width;
                *height = ctx->s_frame.f_height;
                return ffmt;
@@ -684,7 +708,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
        u32 max_sc_h, max_sc_v;
 
        /* In JPEG transparent transfer mode cropping is not supported */
-       if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) {
+       if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) {
                r->width  = sink->f_width;
                r->height = sink->f_height;
                r->left   = r->top = 0;
@@ -847,6 +871,48 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
        return 0;
 }
 
+/**
+ * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters
+ * @sensor: pointer to the sensor subdev
+ * @plane_fmt: provides plane sizes corresponding to the frame layout entries
+ * @try: true to set the frame parameters, false to query only
+ *
+ * This function is used by this driver only for compressed/blob data formats.
+ */
+static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor,
+                                     struct v4l2_plane_pix_format *plane_fmt,
+                                     unsigned int num_planes, bool try)
+{
+       struct v4l2_mbus_frame_desc fd;
+       int i, ret;
+
+       for (i = 0; i < num_planes; i++)
+               fd.entry[i].length = plane_fmt[i].sizeimage;
+
+       if (try)
+               ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd);
+       else
+               ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd);
+
+       if (ret < 0)
+               return ret;
+
+       if (num_planes != fd.num_entries)
+               return -EINVAL;
+
+       for (i = 0; i < num_planes; i++)
+               plane_fmt[i].sizeimage = fd.entry[i].length;
+
+       if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) {
+               v4l2_err(sensor->v4l2_dev,  "Unsupported buffer size: %u\n",
+                        fd.entry[0].length);
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
                                 struct v4l2_format *f)
 {
@@ -865,7 +931,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
        struct v4l2_mbus_framefmt mf;
        struct fimc_fmt *ffmt = NULL;
 
-       if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+       if (fimc_jpeg_fourcc(pix->pixelformat)) {
                fimc_capture_try_format(ctx, &pix->width, &pix->height,
                                        NULL, &pix->pixelformat,
                                        FIMC_SD_PAD_SINK);
@@ -879,25 +945,32 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
                return -EINVAL;
 
        if (!fimc->vid_cap.user_subdev_api) {
-               mf.width  = pix->width;
+               mf.width = pix->width;
                mf.height = pix->height;
-               mf.code   = ffmt->mbus_code;
+               mf.code = ffmt->mbus_code;
                fimc_md_graph_lock(fimc);
                fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
                fimc_md_graph_unlock(fimc);
-
-               pix->width       = mf.width;
-               pix->height      = mf.height;
+               pix->width = mf.width;
+               pix->height = mf.height;
                if (ffmt)
                        pix->pixelformat = ffmt->fourcc;
        }
 
        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);
+
        return 0;
 }
 
-static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg)
+static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
+                                       enum fimc_color_fmt color)
 {
+       bool jpeg = fimc_fmt_is_user_defined(color);
+
        ctx->scaler.enabled = !jpeg;
        fimc_ctrls_activate(ctx, !jpeg);
 
@@ -920,7 +993,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
                return -EBUSY;
 
        /* Pre-configure format at camera interface input, for JPEG only */
-       if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+       if (fimc_jpeg_fourcc(pix->pixelformat)) {
                fimc_capture_try_format(ctx, &pix->width, &pix->height,
                                        NULL, &pix->pixelformat,
                                        FIMC_SD_PAD_SINK);
@@ -953,7 +1026,16 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
        }
 
        fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
-       for (i = 0; i < ff->fmt->colplanes; i++)
+
+       if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) {
+               ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
+                                       pix->plane_fmt, ff->fmt->memplanes,
+                                       true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       for (i = 0; i < ff->fmt->memplanes; i++)
                ff->payload[i] = pix->plane_fmt[i].sizeimage;
 
        set_frame_bounds(ff, pix->width, pix->height);
@@ -961,7 +1043,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
        if (!(ctx->state & FIMC_COMPOSE))
                set_frame_crop(ff, 0, 0, pix->width, pix->height);
 
-       fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));
+       fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color);
 
        /* Reset cropping and set format at the camera interface input */
        if (!fimc->vid_cap.user_subdev_api) {
@@ -1063,6 +1145,23 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
                    src_fmt.format.height != sink_fmt.format.height ||
                    src_fmt.format.code != sink_fmt.format.code)
                        return -EPIPE;
+
+               if (sd == fimc->pipeline.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 = &vid_cap->ctx->d_frame;
+                       unsigned int i;
+
+                       ret = fimc_get_sensor_frame_desc(sd, plane_fmt,
+                                                        frame->fmt->memplanes,
+                                                        false);
+                       if (ret < 0)
+                               return -EPIPE;
+
+                       for (i = 0; i < frame->fmt->memplanes; i++)
+                               if (frame->payload[i] < plane_fmt[i].sizeimage)
+                                       return -EPIPE;
+               }
        }
        return 0;
 }
@@ -1132,6 +1231,14 @@ static int fimc_cap_qbuf(struct file *file, void *priv,
        return vb2_qbuf(&fimc->vid_cap.vbq, buf);
 }
 
+static int fimc_cap_expbuf(struct file *file, void *priv,
+                         struct v4l2_exportbuffer *eb)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
+
+       return vb2_expbuf(&fimc->vid_cap.vbq, eb);
+}
+
 static int fimc_cap_dqbuf(struct file *file, void *priv,
                           struct v4l2_buffer *buf)
 {
@@ -1256,6 +1363,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
 
        .vidioc_qbuf                    = fimc_cap_qbuf,
        .vidioc_dqbuf                   = fimc_cap_dqbuf,
+       .vidioc_expbuf                  = fimc_cap_expbuf,
 
        .vidioc_prepare_buf             = fimc_cap_prepare_buf,
        .vidioc_create_bufs             = fimc_cap_create_bufs,
@@ -1424,7 +1532,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
        /* Update RGB Alpha control state and value range */
        fimc_alpha_ctrl_update(ctx);
 
-       fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
+       fimc_capture_mark_jpeg_xfer(ctx, ffmt->color);
 
        ff = fmt->pad == FIMC_SD_PAD_SINK ?
                &ctx->s_frame : &ctx->d_frame;
@@ -1631,13 +1739,15 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
        q = &fimc->vid_cap.vbq;
        memset(q, 0, sizeof(*q));
        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       q->io_modes = VB2_MMAP | VB2_USERPTR;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
        q->drv_priv = fimc->vid_cap.ctx;
        q->ops = &fimc_capture_qops;
        q->mem_ops = &vb2_dma_contig_memops;
        q->buf_struct_size = sizeof(struct fimc_vid_buffer);
 
-       vb2_queue_init(q);
+       ret = vb2_queue_init(q);
+       if (ret)
+               goto err_ent;
 
        vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
        ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);