From 4ba289cf4940b6b8ddf1e332fc7248a27f54cfc8 Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Wed, 10 Oct 2018 15:44:56 +0200 Subject: [PATCH] meson: vdec: allow subscribing to V4L2_EVENT_SOURCE_CHANGE Flag MPEG1/MPEG2 as NO_SOURCE_CHANGE. --- drivers/media/platform/meson/vdec/vdec.c | 20 ++++++++++++++-- drivers/media/platform/meson/vdec/vdec.h | 13 +++++++++++ drivers/media/platform/meson/vdec/vdec_helpers.c | 28 +++++++++++++++++++++++ drivers/media/platform/meson/vdec/vdec_helpers.h | 1 + drivers/media/platform/meson/vdec/vdec_platform.c | 6 +++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c index 1c5d3e9..ca64045 100644 --- a/drivers/media/platform/meson/vdec/vdec.c +++ b/drivers/media/platform/meson/vdec/vdec.c @@ -230,7 +230,8 @@ static int vdec_queue_setup(struct vb2_queue *q, * are free to choose any of them to write frames to. As such, * we need all of them to be queued into the driver */ - q->min_buffers_needed = q->num_buffers + *num_buffers; + sess->num_dst_bufs = q->num_buffers + *num_buffers; + q->min_buffers_needed = sess->num_dst_bufs; break; default: return -EINVAL; @@ -260,6 +261,7 @@ static void vdec_vb2_buf_queue(struct vb2_buffer *vb) static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) { struct amvdec_session *sess = vb2_get_drv_priv(q); + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; struct amvdec_core *core = sess->core; struct vb2_v4l2_buffer *buf; int ret; @@ -277,6 +279,13 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) if (!sess->streamon_out || !sess->streamon_cap) return 0; + if (sess->status == STATUS_NEEDS_RESUME && + q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + codec_ops->resume(sess); + sess->status = STATUS_RUNNING; + return 0; + } + sess->vififo_size = SIZE_VIFIFO; sess->vififo_vaddr = dma_alloc_coherent(sess->core->dev, sess->vififo_size, @@ -305,6 +314,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) sess->recycle_thread = kthread_run(vdec_recycle_thread, sess, "vdec_recycle"); + sess->status = STATUS_RUNNING; core->cur_sess = sess; return 0; @@ -362,7 +372,9 @@ static void vdec_stop_streaming(struct vb2_queue *q) struct amvdec_core *core = sess->core; struct vb2_v4l2_buffer *buf; - if (sess->streamon_out && sess->streamon_cap) { + if (sess->status == STATUS_RUNNING || + (sess->status == STATUS_NEEDS_RESUME && + (!sess->streamon_out || !sess->streamon_cap))) { if (vdec_codec_needs_recycle(sess)) kthread_stop(sess->recycle_thread); @@ -375,6 +387,7 @@ static void vdec_stop_streaming(struct vb2_queue *q) kfree(sess->priv); sess->priv = NULL; core->cur_sess = NULL; + sess->status = STATUS_STOPPED; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -611,6 +624,7 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) fmt_out = &platform->formats[f->index]; f->pixelformat = fmt_out->pixfmt; + f->flags = fmt_out->flags; } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt_out = sess->fmt_out; if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index]) @@ -703,6 +717,8 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); default: return -EINVAL; } diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h index 6be7de2..8f8ce62 100644 --- a/drivers/media/platform/meson/vdec/vdec.h +++ b/drivers/media/platform/meson/vdec/vdec.h @@ -101,6 +101,7 @@ struct amvdec_ops { u32 (*vififo_level)(struct amvdec_session *sess); }; + /** * struct amvdec_codec_ops - codec operations * @@ -127,6 +128,7 @@ struct amvdec_codec_ops { int (*can_recycle)(struct amvdec_core *core); void (*recycle)(struct amvdec_core *core, u32 buf_idx); void (*drain)(struct amvdec_session *sess); + void (*resume)(struct amvdec_session *sess); const u8 * (*eos_sequence)(u32 *len); irqreturn_t (*isr)(struct amvdec_session *sess); irqreturn_t (*threaded_isr)(struct amvdec_session *sess); @@ -140,6 +142,7 @@ struct amvdec_codec_ops { * @max_buffers: maximum amount of CAPTURE (dst) buffers * @max_width: maximum picture width supported * @max_height: maximum picture height supported + * @flags: enum flags associated with this pixfmt * @vdec_ops: the VDEC operations that support this format * @codec_ops: the codec operations that support this format * @firmware_path: Path to the firmware that supports this format @@ -151,6 +154,7 @@ struct amvdec_format { u32 max_buffers; u32 max_width; u32 max_height; + u32 flags; struct amvdec_ops *vdec_ops; struct amvdec_codec_ops *codec_ops; @@ -159,6 +163,12 @@ struct amvdec_format { u32 pixfmts_cap[4]; }; +enum amvdec_status { + STATUS_STOPPED, + STATUS_RUNNING, + STATUS_NEEDS_RESUME, +}; + /** * struct amvdec_session - decoding session parameters * @@ -195,6 +205,7 @@ struct amvdec_format { * @timestamps: chronological list of src timestamps * @ts_spinlock: spinlock for the timestamps list * @last_irq_jiffies: tracks last time the vdec triggered an IRQ + * @status: current decoding status * @priv: codec private data */ struct amvdec_session { @@ -225,6 +236,7 @@ struct amvdec_session { unsigned int sequence_cap; unsigned int should_stop; unsigned int keyframe_found; + unsigned int num_dst_bufs; u8 canvas_alloc[MAX_CANVAS]; u32 canvas_num; @@ -245,6 +257,7 @@ struct amvdec_session { u32 wrap_count; u32 dpb_size; + enum amvdec_status status; void *priv; }; diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c index 02090c5..b982b28 100644 --- a/drivers/media/platform/meson/vdec/vdec_helpers.c +++ b/drivers/media/platform/meson/vdec/vdec_helpers.c @@ -403,6 +403,34 @@ void amvdec_set_par_from_dar(struct amvdec_session *sess, } EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar); +void amvdec_src_change(struct amvdec_session *sess, u32 width, u32 height, u32 dpb_size) +{ + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; + + sess->dpb_size = dpb_size; + + /* Check if the capture queue is already configured well for our + * usecase. If so, keep decoding with it and do not send the event + */ + if (sess->width == width && + sess->height == height && + dpb_size <= sess->num_dst_bufs) { + sess->fmt_out->codec_ops->resume(sess); + return; + } + + sess->width = width; + sess->height = height; + sess->status = STATUS_NEEDS_RESUME; + + dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n", + width, height, dpb_size); + v4l2_event_queue_fh(&sess->fh, &ev); +} +EXPORT_SYMBOL_GPL(amvdec_src_change); + void amvdec_abort(struct amvdec_session *sess) { dev_info(sess->core->dev, "Aborting decoding session!\n"); diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h index b9250a8..060799b 100644 --- a/drivers/media/platform/meson/vdec/vdec_helpers.h +++ b/drivers/media/platform/meson/vdec/vdec_helpers.h @@ -44,5 +44,6 @@ void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); void amvdec_set_par_from_dar(struct amvdec_session *sess, u32 dar_num, u32 dar_den); +void amvdec_src_change(struct amvdec_session *sess, u32 width, u32 height, u32 dpb_size); void amvdec_abort(struct amvdec_session *sess); #endif diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c index 46eeb74..291f1ee 100644 --- a/drivers/media/platform/meson/vdec/vdec_platform.c +++ b/drivers/media/platform/meson/vdec/vdec_platform.c @@ -17,6 +17,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc", @@ -27,6 +28,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc", @@ -41,6 +43,7 @@ static const struct amvdec_format vdec_formats_gxl[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc", @@ -51,6 +54,7 @@ static const struct amvdec_format vdec_formats_gxl[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc", @@ -65,6 +69,7 @@ static const struct amvdec_format vdec_formats_gxm[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc", @@ -75,6 +80,7 @@ static const struct amvdec_format vdec_formats_gxm[] = { .max_buffers = 8, .max_width = 1920, .max_height = 1080, + .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE, .vdec_ops = &vdec_1_ops, .codec_ops = &codec_mpeg12_ops, .firmware_path = "meson/gx/vmpeg12_mc",