X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?p=kvmfornfv.git;a=blobdiff_plain;f=kernel%2Fdrivers%2Fmedia%2Fplatform%2Fcoda%2Fcoda-common.c;h=15516a6e3a3916c090762d360ee10fdaeba0efbc;hp=8e6fe0200117f671eb223b3289c63d7ee0073651;hb=e09b41010ba33a20a87472ee821fa407a5b8da36;hpb=f93b97fd65072de626c074dbe099a1fff05ce060 diff --git a/kernel/drivers/media/platform/coda/coda-common.c b/kernel/drivers/media/platform/coda/coda-common.c index 8e6fe0200..15516a6e3 100644 --- a/kernel/drivers/media/platform/coda/coda-common.c +++ b/kernel/drivers/media/platform/coda/coda-common.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -61,10 +62,9 @@ int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); -struct coda_fmt { - char *name; - u32 fourcc; -}; +static int disable_tiling; +module_param(disable_tiling, int, 0644); +MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); void coda_write(struct coda_dev *dev, u32 data, u32 reg) { @@ -84,23 +84,23 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) } void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, - struct vb2_buffer *buf, unsigned int reg_y) + struct vb2_v4l2_buffer *buf, unsigned int reg_y) { - u32 base_y = vb2_dma_contig_plane_dma_addr(buf, 0); + u32 base_y = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); u32 base_cb, base_cr; switch (q_data->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - base_cr = base_y + q_data->bytesperline * q_data->height; - base_cb = base_cr + q_data->bytesperline * q_data->height / 4; - break; - case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: default: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 4; break; + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + base_cr = base_y + q_data->bytesperline * q_data->height; + base_cb = base_cr + q_data->bytesperline * q_data->height / 4; + break; case V4L2_PIX_FMT_YUV422P: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 2; @@ -111,40 +111,6 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, coda_write(ctx->dev, base_cr, reg_y + 8); } -/* - * Array of all formats supported by any version of Coda: - */ -static const struct coda_fmt coda_formats[] = { - { - .name = "YUV 4:2:0 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:0 Planar, YCrCb", - .fourcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "YUV 4:2:0 Partial interleaved Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - }, - { - .name = "YUV 4:2:2 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - }, - { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - }, - { - .name = "JPEG Encoded Images", - .fourcc = V4L2_PIX_FMT_JPEG, - }, -}; - #define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ { mode, src_fourcc, dst_fourcc, max_w, max_h } @@ -190,9 +156,9 @@ static const struct coda_video_device coda_bit_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, .dst_formats = { V4L2_PIX_FMT_H264, @@ -205,9 +171,9 @@ static const struct coda_video_device coda_bit_jpeg_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, .dst_formats = { @@ -224,9 +190,9 @@ static const struct coda_video_device coda_bit_decoder = { V4L2_PIX_FMT_MPEG4, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, }; @@ -238,9 +204,9 @@ static const struct coda_video_device coda_bit_jpeg_decoder = { V4L2_PIX_FMT_JPEG, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, }; @@ -261,38 +227,21 @@ static const struct coda_video_device *coda9_video_devices[] = { &coda_bit_decoder, }; -static bool coda_format_is_yuv(u32 fourcc) +/* + * Normalize all supported YUV 4:2:0 formats to the value used in the codec + * tables. + */ +static u32 coda_format_normalize_yuv(u32 fourcc) { switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV422P: - return true; + return V4L2_PIX_FMT_YUV420; default: - return false; - } -} - -static const char *coda_format_name(u32 fourcc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_formats); i++) { - if (coda_formats[i].fourcc == fourcc) - return coda_formats[i].name; + return fourcc; } - - return NULL; -} - -/* - * Normalize all supported YUV 4:2:0 formats to the value used in the codec - * tables. - */ -static u32 coda_format_normalize_yuv(u32 fourcc) -{ - return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; } static const struct coda_codec *coda_find_codec(struct coda_dev *dev, @@ -396,7 +345,6 @@ static int coda_enum_fmt(struct file *file, void *priv, struct video_device *vdev = video_devdata(file); const struct coda_video_device *cvd = to_coda_video_device(vdev); const u32 *formats; - const char *name; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) formats = cvd->src_formats; @@ -408,11 +356,7 @@ static int coda_enum_fmt(struct file *file, void *priv, if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) return -EINVAL; - name = coda_format_name(formats[f->index]); - strlcpy(f->description, name, sizeof(f->description)); f->pixelformat = formats[f->index]; - if (!coda_format_is_yuv(formats[f->index])) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -504,9 +448,9 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, S_ALIGN); switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: /* * Frame stride must be at least multiple of 8, * but multiple of 16 for h.264 or JPEG 4:2:x @@ -645,6 +589,22 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) q_data->rect.width = f->fmt.pix.width; q_data->rect.height = f->fmt.pix.height; + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; + if (!disable_tiling) + break; + } + /* else fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; + break; + default: + break; + } + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %d\n", f->type, q_data->width, q_data->height, q_data->fourcc); @@ -724,7 +684,7 @@ static int coda_qbuf(struct file *file, void *priv, } static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, - struct v4l2_buffer *buf) + struct vb2_v4l2_buffer *buf) { struct vb2_queue *src_vq; @@ -734,25 +694,20 @@ static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, (buf->sequence == (ctx->qsequence - 1))); } -static int coda_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, + enum vb2_buffer_state state) { - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; + const struct v4l2_event eos_event = { + .type = V4L2_EVENT_EOS + }; - ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); - - /* If this is the last capture buffer, emit an end-of-stream event */ - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - coda_buf_is_end_of_stream(ctx, buf)) { - const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; + if (coda_buf_is_end_of_stream(ctx, buf)) { + buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_event_queue_fh(&ctx->fh, &eos_event); } - return ret; + v4l2_m2m_buf_done(buf, state); } static int coda_g_selection(struct file *file, void *fh, @@ -836,6 +791,104 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + tpf = &a->parm.output.timeperframe; + tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; + tpf->numerator = 1 + (ctx->params.framerate >> + CODA_FRATE_DIV_OFFSET); + + return 0; +} + +/* + * Approximate timeperframe v4l2_fract with values that can be written + * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. + */ +static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) +{ + struct v4l2_fract s = *timeperframe; + struct v4l2_fract f0; + struct v4l2_fract f1 = { 1, 0 }; + struct v4l2_fract f2 = { 0, 1 }; + unsigned int i, div, s_denominator; + + /* Lower bound is 1/65535 */ + if (s.numerator == 0 || s.denominator / s.numerator > 65535) { + timeperframe->numerator = 1; + timeperframe->denominator = 65535; + return; + } + + /* Upper bound is 65536/1, map everything above to infinity */ + if (s.denominator == 0 || s.numerator / s.denominator > 65536) { + timeperframe->numerator = 1; + timeperframe->denominator = 0; + return; + } + + /* Reduce fraction to lowest terms */ + div = gcd(s.numerator, s.denominator); + if (div > 1) { + s.numerator /= div; + s.denominator /= div; + } + + if (s.numerator <= 65536 && s.denominator < 65536) { + *timeperframe = s; + return; + } + + /* Find successive convergents from continued fraction expansion */ + while (f2.numerator <= 65536 && f2.denominator < 65536) { + f0 = f1; + f1 = f2; + + /* Stop when f2 exactly equals timeperframe */ + if (s.numerator == 0) + break; + + i = s.denominator / s.numerator; + + f2.numerator = f0.numerator + i * f1.numerator; + f2.denominator = f0.denominator + i * f2.denominator; + + s_denominator = s.numerator; + s.numerator = s.denominator % s.numerator; + s.denominator = s_denominator; + } + + *timeperframe = f1; +} + +static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) +{ + return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | + timeperframe->denominator; +} + +static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + tpf = &a->parm.output.timeperframe; + coda_approximate_timeperframe(tpf); + ctx->params.framerate = coda_timeperframe_to_frate(tpf); + + return 0; +} + static int coda_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { @@ -865,7 +918,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_qbuf = coda_qbuf, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = coda_dqbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_streamon = v4l2_m2m_ioctl_streamon, @@ -876,31 +929,13 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_try_decoder_cmd = coda_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, + .vidioc_g_parm = coda_g_parm, + .vidioc_s_parm = coda_s_parm, + .vidioc_subscribe_event = coda_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -void coda_set_gdi_regs(struct coda_ctx *ctx) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - struct coda_dev *dev = ctx->dev; - int i; - - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ca_map[i], - CODA9_GDI_XY2_CAS_0 + 4 * i); - for (i = 0; i < 4; i++) - coda_write(dev, tiled_map->xy2ba_map[i], - CODA9_GDI_XY2_BA_0 + 4 * i); - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ra_map[i], - CODA9_GDI_XY2_RAS_0 + 4 * i); - coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); - for (i = 0; i < 32; i++) - coda_write(dev, tiled_map->rbc2axi_map[i], - CODA9_GDI_RBC2_AXI_0 + 4 * i); -} - /* * Mem-to-mem operations. */ @@ -954,14 +989,14 @@ static void coda_pic_run_work(struct work_struct *work) static int coda_job_ready(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; + int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); /* * For both 'P' and 'key' frame cases 1 picture * and 1 frame are needed. In the decoder case, * the compressed frame can be in the bitstream. */ - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - ctx->inst_type != CODA_INST_DECODER) { + if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "not ready: not enough video buffers.\n"); return 0; @@ -974,27 +1009,17 @@ static int coda_job_ready(void *m2m_priv) } if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { - struct list_head *meta; - bool stream_end; - int num_metas; - int src_bufs; + bool stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + int num_metas = ctx->num_metas; - if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + if (ctx->hold && !src_bufs) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: on hold for more buffers.\n", ctx->idx); return 0; } - stream_end = ctx->bit_stream_param & - CODA_BIT_STREAM_END_FLAG; - - num_metas = 0; - list_for_each(meta, &ctx->buffer_meta_list) - num_metas++; - - src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); - if (!stream_end && (num_metas + src_bufs) < 2) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: need 2 buffers available (%d, %d)\n", @@ -1003,8 +1028,8 @@ static int coda_job_ready(void *m2m_priv) } - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - !stream_end && (coda_get_bitstream_payload(ctx) < 512)) { + if (!src_bufs && !stream_end && + (coda_get_bitstream_payload(ctx) < 512)) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: not enough bitstream data (%d).\n", ctx->idx, coda_get_bitstream_payload(ctx)); @@ -1020,6 +1045,7 @@ static int coda_job_ready(void *m2m_priv) v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "job ready\n"); + return 1; } @@ -1057,32 +1083,6 @@ static const struct v4l2_m2m_ops coda_m2m_ops = { .unlock = coda_unlock, }; -static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - int luma_map, chro_map, i; - - memset(tiled_map, 0, sizeof(*tiled_map)); - - luma_map = 64; - chro_map = 64; - tiled_map->map_type = tiled_map_type; - for (i = 0; i < 16; i++) - tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 4; i++) - tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 16; i++) - tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map; - - if (tiled_map_type == GDI_LINEAR_FRAME_MAP) { - tiled_map->xy2rbc_config = 0; - } else { - dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n", - tiled_map_type); - return; - } -} - static void set_default_params(struct coda_ctx *ctx) { unsigned int max_w, max_h, usize, csize; @@ -1099,8 +1099,8 @@ static void set_default_params(struct coda_ctx *ctx) ctx->params.framerate = 30; /* Default formats for output and input queues */ - ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; - ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; + ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; + ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; ctx->q_data[V4L2_M2M_SRC].width = max_w; ctx->q_data[V4L2_M2M_SRC].height = max_h; ctx->q_data[V4L2_M2M_DST].width = max_w; @@ -1121,15 +1121,17 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].rect.width = max_w; ctx->q_data[V4L2_M2M_DST].rect.height = max_h; - if (ctx->dev->devtype->product == CODA_960) - coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); + /* + * Since the RBC2AXI logic only supports a single chroma plane, + * macroblock tiling only works for to NV12 pixel format. + */ + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; } /* * Queue operations */ -static int coda_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, +static int coda_queue_setup(struct vb2_queue *vq, const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -1172,6 +1174,7 @@ static int coda_buf_prepare(struct vb2_buffer *vb) static void coda_buf_queue(struct vb2_buffer *vb) { + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_queue *vq = vb->vb2_queue; struct coda_q_data *q_data; @@ -1190,12 +1193,12 @@ static void coda_buf_queue(struct vb2_buffer *vb) if (vb2_get_plane_payload(vb, 0) == 0) coda_bit_stream_end_flag(ctx); mutex_lock(&ctx->bitstream_mutex); - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); if (vb2_is_streaming(vb->vb2_queue)) coda_fill_bitstream(ctx, true); mutex_unlock(&ctx->bitstream_mutex); } else { - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } } @@ -1244,14 +1247,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_buffer *buf; + struct vb2_v4l2_buffer *buf; int ret = 0; q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || - (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - ctx->dev->devtype->product == CODA_7541)) { + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { /* copy the buffers that were queued before streamon */ mutex_lock(&ctx->bitstream_mutex); coda_fill_bitstream(ctx, false); @@ -1320,7 +1321,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) goto err; } - ctx->initialized = 1; return ret; err: @@ -1338,7 +1338,8 @@ static void coda_stop_streaming(struct vb2_queue *q) { struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; - struct vb2_buffer *buf; + struct vb2_v4l2_buffer *buf; + unsigned long flags; bool stop; stop = ctx->streamon_out && ctx->streamon_cap; @@ -1373,20 +1374,23 @@ static void coda_stop_streaming(struct vb2_queue *q) queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } - mutex_lock(&ctx->bitstream_mutex); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); kfree(meta); } - mutex_unlock(&ctx->bitstream_mutex); + ctx->num_metas = 0; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); - ctx->initialized = 0; ctx->runcounter = 0; ctx->aborting = 0; } + + if (!ctx->streamon_out && !ctx->streamon_cap) + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; } static const struct vb2_ops coda_qops = { @@ -1474,6 +1478,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_JPEG_RESTART_INTERVAL: ctx->params.jpeg_restart_interval = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: + ctx->params.vbv_delay = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); + break; default: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", @@ -1533,6 +1543,14 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); + /* + * The maximum VBV size value is 0x7fffffff bits, + * one bit less than 262144 KiB + */ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); } static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) @@ -1731,6 +1749,7 @@ static int coda_open(struct file *file) mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); + spin_lock_init(&ctx->buffer_meta_lock); coda_lock(ctx); list_add(&ctx->list, &dev->instances); @@ -1774,7 +1793,7 @@ static int coda_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized && ctx->ops->seq_end_work) { + if (ctx->ops->seq_end_work) { queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } @@ -2160,9 +2179,9 @@ static int coda_probe(struct platform_device *pdev) } /* Get IRAM pool from device tree or platform data */ - pool = of_get_named_gen_pool(np, "iram", 0); + pool = of_gen_pool_get(np, "iram", 0); if (!pool && pdata) - pool = dev_get_gen_pool(pdata->iram_dev); + pool = gen_pool_get(pdata->iram_dev, NULL); if (!pool) { dev_err(&pdev->dev, "iram pool not available\n"); return -ENOMEM;