diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-04 06:59:38 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-04 06:59:38 +0300 |
commit | a98f670e41a99f53acb1fb33cee9c6abbb2e6f23 (patch) | |
tree | f8ae10a4cb91758ad7f9422053753a8c5d0f04dc /drivers/media/platform/qcom | |
parent | ee01c4d72adffb7d424535adf630f2955748fa8b (diff) | |
parent | 938b29db3aa9c293c7c1366b16e55e308f1a1ddd (diff) | |
download | linux-a98f670e41a99f53acb1fb33cee9c6abbb2e6f23.tar.xz |
Merge tag 'media/v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Media documentation is now split into admin-guide, driver-api and
userspace-api books (a longstanding request from Jon);
- The media Kconfig was reorganized, in order to make easier to select
drivers and their dependencies;
- The testing drivers now has a separate directory;
- added a new driver for Rockchip Video Decoder IP;
- The atomisp staging driver was resurrected. It is meant to work with
4 generations of cameras on Atom-based laptops, tablets and cell
phones. So, it seems worth investing time to cleanup this driver and
making it in good shape.
- Added some V4L2 core ancillary routines to help with h264 codecs;
- Added an ov2740 image sensor driver;
- The si2157 gained support for Analog TV, which, in turn, added
support for some cx231xx and cx23885 boards to also support analog
standards;
- Added some V4L2 controls (V4L2_CID_CAMERA_ORIENTATION and
V4L2_CID_CAMERA_SENSOR_ROTATION) to help identifying where the camera
is located at the device;
- VIDIOC_ENUM_FMT was extended to support MC-centric devices;
- Lots of drivers improvements and cleanups.
* tag 'media/v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (503 commits)
media: Documentation: media: Refer to mbus format documentation from CSI-2 docs
media: s5k5baf: Replace zero-length array with flexible-array
media: i2c: imx219: Drop <linux/clk-provider.h> and <linux/clkdev.h>
media: i2c: Add ov2740 image sensor driver
media: ov8856: Implement sensor module revision identification
media: ov8856: Add devicetree support
media: dt-bindings: ov8856: Document YAML bindings
media: dvb-usb: Add Cinergy S2 PCIe Dual Port support
media: dvbdev: Fix tuner->demod media controller link
media: dt-bindings: phy: phy-rockchip-dphy-rx0: move rockchip dphy rx0 bindings out of staging
media: staging: dt-bindings: phy-rockchip-dphy-rx0: remove non-used reg property
media: atomisp: unify the version for isp2401 a0 and b0 versions
media: atomisp: update TODO with the current data
media: atomisp: adjust some code at sh_css that could be broken
media: atomisp: don't produce errs for ignored IRQs
media: atomisp: print IRQ when debugging
media: atomisp: isp_mmu: don't use kmem_cache
media: atomisp: add a notice about possible leak resources
media: atomisp: disable the dynamic and reserved pools
media: atomisp: turn on camera before setting it
...
Diffstat (limited to 'drivers/media/platform/qcom')
-rw-r--r-- | drivers/media/platform/qcom/venus/core.c | 21 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/core.h | 7 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/helpers.c | 18 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/helpers.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi.c | 10 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi.h | 3 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_cmds.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_msgs.c | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_msgs.h | 10 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/vdec.c | 200 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/venc.c | 10 |
11 files changed, 229 insertions, 56 deletions
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 194b10b98767..203c6538044f 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -210,6 +210,8 @@ static int venus_probe(struct platform_device *pdev) if (!core->res) return -ENODEV; + mutex_init(&core->pm_lock); + core->pm_ops = venus_pm_get(core->res->hfi_version); if (!core->pm_ops) return -ENODEV; @@ -242,10 +244,6 @@ static int venus_probe(struct platform_device *pdev) if (ret) return ret; - ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); - if (ret) - return ret; - ret = hfi_create(core, &venus_core_ops); if (ret) return ret; @@ -320,7 +318,6 @@ static int venus_remove(struct platform_device *pdev) ret = hfi_core_deinit(core, true); WARN_ON(ret); - hfi_destroy(core); venus_shutdown(core); of_platform_depopulate(dev); @@ -332,10 +329,14 @@ static int venus_remove(struct platform_device *pdev) if (pm_ops->core_put) pm_ops->core_put(dev); + hfi_destroy(core); + icc_put(core->video_path); icc_put(core->cpucfg_path); v4l2_device_unregister(&core->v4l2_dev); + mutex_destroy(&core->pm_lock); + mutex_destroy(&core->lock); return ret; } @@ -350,6 +351,10 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) if (ret) return ret; + ret = icc_set_bw(core->cpucfg_path, 0, 0); + if (ret) + return ret; + if (pm_ops->core_power) ret = pm_ops->core_power(dev, POWER_OFF); @@ -368,6 +373,10 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) return ret; } + ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); + if (ret) + return ret; + return hfi_core_resume(core, false); } @@ -447,7 +456,7 @@ static const struct freq_tbl sdm845_freq_table[] = { { 244800, 100000000 }, /* 1920x1080@30 */ }; -static struct codec_freq_data sdm845_codec_freq_data[] = { +static const struct codec_freq_data sdm845_codec_freq_data[] = { { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 }, { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 }, { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 }, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index bd3ac6a4501f..7118612673c9 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -128,6 +128,7 @@ struct venus_caps { * @error: an error returned during last HFI sync operations * @sys_error: an error flag that signal system error event * @core_ops: the core operations + * @pm_lock: a lock for PM operations * @enc_codecs: encoders supported by this core * @dec_codecs: decoders supported by this core * @max_sessions_supported: holds the maximum number of sessions @@ -168,6 +169,7 @@ struct venus_core { bool sys_error; const struct hfi_core_ops *core_ops; const struct venus_pm_ops *pm_ops; + struct mutex pm_lock; unsigned long enc_codecs; unsigned long dec_codecs; unsigned int max_sessions_supported; @@ -259,7 +261,8 @@ enum venus_dec_state { VENUS_DEC_STATE_SEEK = 4, VENUS_DEC_STATE_DRAIN = 5, VENUS_DEC_STATE_DECODING = 6, - VENUS_DEC_STATE_DRC = 7 + VENUS_DEC_STATE_DRC = 7, + VENUS_DEC_STATE_DRC_FLUSH_DONE = 8, }; struct venus_ts_metadata { @@ -324,6 +327,7 @@ struct venus_ts_metadata { * @priv: a private for HFI operations callbacks * @session_type: the type of the session (decoder or encoder) * @hprop: a union used as a holder by get property + * @last_buf: last capture buffer for dynamic-resoluton-change */ struct venus_inst { struct list_head list; @@ -385,6 +389,7 @@ struct venus_inst { union hfi_get_property hprop; unsigned int core_acquired: 1; unsigned int bit_depth; + struct vb2_buffer *last_buf; }; #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index bcc603804041..0143af7822b2 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1129,15 +1129,18 @@ unlock: } EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_queue); -void venus_helper_buffers_done(struct venus_inst *inst, +void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type, enum vb2_buffer_state state) { struct vb2_v4l2_buffer *buf; - while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx))) - v4l2_m2m_buf_done(buf, state); - while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx))) - v4l2_m2m_buf_done(buf, state); + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + while ((buf = v4l2_m2m_src_buf_remove(inst->m2m_ctx))) + v4l2_m2m_buf_done(buf, state); + } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx))) + v4l2_m2m_buf_done(buf, state); + } } EXPORT_SYMBOL_GPL(venus_helper_buffers_done); @@ -1168,7 +1171,10 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) INIT_LIST_HEAD(&inst->registeredbufs); } - venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR); + venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + VB2_BUF_STATE_ERROR); + venus_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + VB2_BUF_STATE_ERROR); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->streamon_out = 0; diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index b64875564064..8fbbda12a4fe 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -14,7 +14,7 @@ struct venus_core; bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt); struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx); -void venus_helper_buffers_done(struct venus_inst *inst, +void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type, enum vb2_buffer_state state); int venus_helper_vb2_buf_init(struct vb2_buffer *vb); int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb); diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 3d8b1284d1f3..a211eb93e0f9 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -382,7 +382,7 @@ int hfi_session_unload_res(struct venus_inst *inst) } EXPORT_SYMBOL_GPL(hfi_session_unload_res); -int hfi_session_flush(struct venus_inst *inst, u32 type) +int hfi_session_flush(struct venus_inst *inst, u32 type, bool block) { const struct hfi_ops *ops = inst->core->ops; int ret; @@ -393,9 +393,11 @@ int hfi_session_flush(struct venus_inst *inst, u32 type) if (ret) return ret; - ret = wait_session_msg(inst); - if (ret) - return ret; + if (block) { + ret = wait_session_msg(inst); + if (ret) + return ret; + } return 0; } diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h index 855822c9f39b..62c315291484 100644 --- a/drivers/media/platform/qcom/venus/hfi.h +++ b/drivers/media/platform/qcom/venus/hfi.h @@ -102,6 +102,7 @@ struct hfi_inst_ops { u32 hfi_flags, u64 timestamp_us); void (*event_notify)(struct venus_inst *inst, u32 event, struct hfi_event_data *data); + void (*flush_done)(struct venus_inst *inst); }; struct hfi_ops { @@ -161,7 +162,7 @@ int hfi_session_continue(struct venus_inst *inst); int hfi_session_abort(struct venus_inst *inst); int hfi_session_load_res(struct venus_inst *inst); int hfi_session_unload_res(struct venus_inst *inst); -int hfi_session_flush(struct venus_inst *inst, u32 type); +int hfi_session_flush(struct venus_inst *inst, u32 type, bool block); int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd); int hfi_session_unset_buffers(struct venus_inst *inst, diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h index cae9d5d61c0c..83705e237f1c 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.h +++ b/drivers/media/platform/qcom/venus/hfi_cmds.h @@ -107,7 +107,7 @@ struct hfi_session_abort_pkt { struct hfi_session_set_property_pkt { struct hfi_session_hdr_pkt shdr; u32 num_properties; - u32 data[0]; + u32 data[]; }; struct hfi_session_set_buffers_pkt { diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 04ef2286efc6..279a9d6fe737 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -439,6 +439,8 @@ static void hfi_session_flush_done(struct venus_core *core, inst->error = pkt->error_type; complete(&inst->done); + if (inst->ops->flush_done) + inst->ops->flush_done(inst); } static void hfi_session_etb_done(struct venus_core *core, diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.h b/drivers/media/platform/qcom/venus/hfi_msgs.h index 7694b1d25d9d..526d9f5b487b 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.h +++ b/drivers/media/platform/qcom/venus/hfi_msgs.h @@ -155,7 +155,7 @@ struct hfi_msg_session_empty_buffer_done_pkt { u32 input_tag; u32 packet_buffer; u32 extradata_buffer; - u32 data[0]; + u32 data[]; }; struct hfi_msg_session_fbd_compressed_pkt { @@ -175,7 +175,7 @@ struct hfi_msg_session_fbd_compressed_pkt { u32 picture_type; u32 packet_buffer; u32 extradata_buffer; - u32 data[0]; + u32 data[]; }; struct hfi_msg_session_fbd_uncompressed_plane0_pkt { @@ -202,7 +202,7 @@ struct hfi_msg_session_fbd_uncompressed_plane0_pkt { u32 picture_type; u32 packet_buffer; u32 extradata_buffer; - u32 data[0]; + u32 data[]; }; struct hfi_msg_session_fbd_uncompressed_plane1_pkt { @@ -211,7 +211,7 @@ struct hfi_msg_session_fbd_uncompressed_plane1_pkt { u32 filled_len; u32 offset; u32 packet_buffer2; - u32 data[0]; + u32 data[]; }; struct hfi_msg_session_fbd_uncompressed_plane2_pkt { @@ -220,7 +220,7 @@ struct hfi_msg_session_fbd_uncompressed_plane2_pkt { u32 filled_len; u32 offset; u32 packet_buffer3; - u32 data[0]; + u32 data[]; }; struct hfi_msg_session_parse_sequence_header_done_pkt { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 4ed2628585a1..7c4c483d5438 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -276,6 +276,14 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) const struct venus_format *fmt; struct v4l2_format format; u32 pixfmt_out = 0, pixfmt_cap = 0; + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + if (!q) + return -EINVAL; + + if (vb2_is_busy(q)) + return -EBUSY; orig_pixmp = *pixmp; @@ -545,6 +553,64 @@ static const struct v4l2_ioctl_ops vdec_ioctl_ops = { .vidioc_decoder_cmd = vdec_decoder_cmd, }; +static int vdec_pm_get(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_dec; + int ret; + + mutex_lock(&core->pm_lock); + ret = pm_runtime_get_sync(dev); + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static int vdec_pm_put(struct venus_inst *inst, bool autosuspend) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_dec; + int ret; + + mutex_lock(&core->pm_lock); + + if (autosuspend) + ret = pm_runtime_put_autosuspend(dev); + else + ret = pm_runtime_put_sync(dev); + + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static int vdec_pm_get_put(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + struct device *dev = core->dev_dec; + int ret = 0; + + mutex_lock(&core->pm_lock); + + if (pm_runtime_suspended(dev)) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto error; + + ret = pm_runtime_put_autosuspend(dev); + } + +error: + mutex_unlock(&core->pm_lock); + + return ret < 0 ? ret : 0; +} + +static void vdec_pm_touch(struct venus_inst *inst) +{ + pm_runtime_mark_last_busy(inst->core->dev_dec); +} + static int vdec_set_properties(struct venus_inst *inst) { struct vdec_controls *ctr = &inst->controls.dec; @@ -746,12 +812,20 @@ static int vdec_queue_setup(struct vb2_queue *q, return 0; } - ret = vdec_session_init(inst); + ret = vdec_pm_get(inst); if (ret) return ret; + ret = vdec_session_init(inst); + if (ret) + goto put_power; + ret = vdec_num_buffers(inst, &in_num, &out_num); if (ret) + goto put_power; + + ret = vdec_pm_put(inst, false); + if (ret) return ret; switch (q->type) { @@ -786,6 +860,10 @@ static int vdec_queue_setup(struct vb2_queue *q, } return ret; + +put_power: + vdec_pm_put(inst, false); + return ret; } static int vdec_verify_conf(struct venus_inst *inst) @@ -836,7 +914,7 @@ static int vdec_start_capture(struct venus_inst *inst) return 0; reconfigure: - ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT); + ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, true); if (ret) return ret; @@ -947,14 +1025,23 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) mutex_lock(&inst->lock); - ret = venus_pm_acquire_core(inst); - if (ret) - goto error; - - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ret = vdec_start_capture(inst); - else + } else { + ret = vdec_pm_get(inst); + if (ret) + goto error; + + ret = venus_pm_acquire_core(inst); + if (ret) + goto put_power; + + ret = vdec_pm_put(inst, true); + if (ret) + goto error; + ret = vdec_start_output(inst); + } if (ret) goto error; @@ -962,8 +1049,10 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) mutex_unlock(&inst->lock); return 0; +put_power: + vdec_pm_put(inst, false); error: - venus_helper_buffers_done(inst, VB2_BUF_STATE_QUEUED); + venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); mutex_unlock(&inst->lock); return ret; } @@ -982,23 +1071,25 @@ static int vdec_stop_capture(struct venus_inst *inst) switch (inst->codec_state) { case VENUS_DEC_STATE_DECODING: - ret = hfi_session_flush(inst, HFI_FLUSH_ALL); + ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true); /* fallthrough */ case VENUS_DEC_STATE_DRAIN: vdec_cancel_dst_buffers(inst); inst->codec_state = VENUS_DEC_STATE_STOPPED; break; case VENUS_DEC_STATE_DRC: - ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT); - vdec_cancel_dst_buffers(inst); + WARN_ON(1); + fallthrough; + case VENUS_DEC_STATE_DRC_FLUSH_DONE: inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP; - INIT_LIST_HEAD(&inst->registeredbufs); venus_helper_free_dpb_bufs(inst); break; default: - return 0; + break; } + INIT_LIST_HEAD(&inst->registeredbufs); + return ret; } @@ -1010,12 +1101,12 @@ static int vdec_stop_output(struct venus_inst *inst) case VENUS_DEC_STATE_DECODING: case VENUS_DEC_STATE_DRAIN: case VENUS_DEC_STATE_STOPPED: - ret = hfi_session_flush(inst, HFI_FLUSH_ALL); + ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true); inst->codec_state = VENUS_DEC_STATE_SEEK; break; case VENUS_DEC_STATE_INIT: case VENUS_DEC_STATE_CAPTURE_SETUP: - ret = hfi_session_flush(inst, HFI_FLUSH_INPUT); + ret = hfi_session_flush(inst, HFI_FLUSH_INPUT, true); break; default: break; @@ -1036,7 +1127,7 @@ static void vdec_stop_streaming(struct vb2_queue *q) else ret = vdec_stop_output(inst); - venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR); + venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); if (ret) goto unlock; @@ -1055,8 +1146,9 @@ static void vdec_session_release(struct venus_inst *inst) struct venus_core *core = inst->core; int ret, abort = 0; - mutex_lock(&inst->lock); + vdec_pm_get(inst); + mutex_lock(&inst->lock); inst->codec_state = VENUS_DEC_STATE_DEINIT; ret = hfi_session_stop(inst); @@ -1078,10 +1170,11 @@ static void vdec_session_release(struct venus_inst *inst) venus_helper_free_dpb_bufs(inst); venus_pm_load_scale(inst); - venus_pm_release_core(inst); INIT_LIST_HEAD(&inst->registeredbufs); - mutex_unlock(&inst->lock); + + venus_pm_release_core(inst); + vdec_pm_put(inst, false); } static int vdec_buf_init(struct vb2_buffer *vb) @@ -1102,6 +1195,15 @@ static void vdec_buf_cleanup(struct vb2_buffer *vb) vdec_session_release(inst); } +static void vdec_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + + vdec_pm_get_put(inst); + + venus_helper_vb2_buf_queue(vb); +} + static const struct vb2_ops vdec_vb2_ops = { .queue_setup = vdec_queue_setup, .buf_init = vdec_buf_init, @@ -1109,7 +1211,7 @@ static const struct vb2_ops vdec_vb2_ops = { .buf_prepare = venus_helper_vb2_buf_prepare, .start_streaming = vdec_start_streaming, .stop_streaming = vdec_stop_streaming, - .buf_queue = venus_helper_vb2_buf_queue, + .buf_queue = vdec_vb2_buf_queue, }; static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, @@ -1121,6 +1223,8 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, struct vb2_buffer *vb; unsigned int type; + vdec_pm_touch(inst); + if (buf_type == HFI_BUFFER_INPUT) type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; else @@ -1140,6 +1244,13 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; + if (inst->last_buf == vb) { + inst->last_buf = NULL; + vbuf->flags |= V4L2_BUF_FLAG_LAST; + vb2_set_plane_payload(vb, 0, 0); + vb->timestamp = 0; + } + if (vbuf->flags & V4L2_BUF_FLAG_LAST) { const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; @@ -1148,6 +1259,9 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, if (inst->codec_state == VENUS_DEC_STATE_DRAIN) inst->codec_state = VENUS_DEC_STATE_STOPPED; } + + if (!bytesused) + state = VB2_BUF_STATE_ERROR; } else { vbuf->sequence = inst->sequence_out++; } @@ -1214,6 +1328,25 @@ static void vdec_event_change(struct venus_inst *inst, } } + /* + * The assumption is that the firmware have to return the last buffer + * before this event is received in the v4l2 driver. Also the firmware + * itself doesn't mark the last decoder output buffer with HFI EOS flag. + */ + + if (!sufficient && inst->codec_state == VENUS_DEC_STATE_DRC) { + struct vb2_v4l2_buffer *last; + int ret; + + last = v4l2_m2m_last_dst_buf(inst->m2m_ctx); + if (last) + inst->last_buf = &last->vb2_buf; + + ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, false); + if (ret) + dev_dbg(dev, "flush output error %d\n", ret); + } + inst->reconfig = true; v4l2_event_queue_fh(&inst->fh, &ev); wake_up(&inst->reconf_wait); @@ -1227,6 +1360,8 @@ static void vdec_event_notify(struct venus_inst *inst, u32 event, struct venus_core *core = inst->core; struct device *dev = core->dev_dec; + vdec_pm_touch(inst); + switch (event) { case EVT_SESSION_ERROR: inst->session_error = true; @@ -1252,9 +1387,16 @@ static void vdec_event_notify(struct venus_inst *inst, u32 event, } } +static void vdec_flush_done(struct venus_inst *inst) +{ + if (inst->codec_state == VENUS_DEC_STATE_DRC) + inst->codec_state = VENUS_DEC_STATE_DRC_FLUSH_DONE; +} + static const struct hfi_inst_ops vdec_hfi_ops = { .buf_done = vdec_buf_done, .event_notify = vdec_event_notify, + .flush_done = vdec_flush_done, }; static void vdec_inst_init(struct venus_inst *inst) @@ -1347,13 +1489,9 @@ static int vdec_open(struct file *file) init_waitqueue_head(&inst->reconf_wait); venus_helper_init_instance(inst); - ret = pm_runtime_get_sync(core->dev_dec); - if (ret < 0) - goto err_free_inst; - ret = vdec_ctrl_init(inst); if (ret) - goto err_put_sync; + goto err_free; ret = hfi_session_create(inst, &vdec_hfi_ops); if (ret) @@ -1392,9 +1530,7 @@ err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: vdec_ctrl_deinit(inst); -err_put_sync: - pm_runtime_put_sync(core->dev_dec); -err_free_inst: +err_free: kfree(inst); return ret; } @@ -1403,6 +1539,8 @@ static int vdec_close(struct file *file) { struct venus_inst *inst = to_inst(file); + vdec_pm_get(inst); + v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); vdec_ctrl_deinit(inst); @@ -1411,7 +1549,7 @@ static int vdec_close(struct file *file) v4l2_fh_del(&inst->fh); v4l2_fh_exit(&inst->fh); - pm_runtime_put_sync(inst->core->dev_dec); + vdec_pm_put(inst, false); kfree(inst); return 0; @@ -1468,6 +1606,8 @@ static int vdec_probe(struct platform_device *pdev) core->dev_dec = dev; video_set_drvdata(vdev, core); + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); return 0; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 9981a2a27c90..feed648550d1 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -357,6 +357,14 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) const struct venus_format *fmt; struct v4l2_format format; u32 pixfmt_out = 0, pixfmt_cap = 0; + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + if (!q) + return -EINVAL; + + if (vb2_is_busy(q)) + return -EBUSY; orig_pixmp = *pixmp; @@ -1018,7 +1026,7 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) deinit_sess: hfi_session_deinit(inst); bufs_done: - venus_helper_buffers_done(inst, VB2_BUF_STATE_QUEUED); + venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->streamon_out = 0; else |