diff options
Diffstat (limited to 'drivers/media/platform/qcom/venus')
-rw-r--r-- | drivers/media/platform/qcom/venus/core.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/core.h | 10 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/firmware.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/helpers.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_cmds.c | 23 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_helper.h | 18 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/vdec.c | 29 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/venc.c | 115 |
9 files changed, 181 insertions, 32 deletions
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 990a1519f968..2ae867cb4c48 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -416,7 +416,7 @@ err_core_put: return ret; } -static int venus_remove(struct platform_device *pdev) +static void venus_remove(struct platform_device *pdev) { struct venus_core *core = platform_get_drvdata(pdev); const struct venus_pm_ops *pm_ops = core->pm_ops; @@ -447,8 +447,6 @@ static int venus_remove(struct platform_device *pdev) mutex_destroy(&core->pm_lock); mutex_destroy(&core->lock); venus_dbgfs_deinit(core); - - return ret; } static void venus_core_shutdown(struct platform_device *pdev) @@ -891,7 +889,7 @@ MODULE_DEVICE_TABLE(of, venus_dt_match); static struct platform_driver qcom_venus_driver = { .probe = venus_probe, - .remove = venus_remove, + .remove_new = venus_remove, .driver = { .name = "qcom-venus", .of_match_table = venus_dt_match, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 32551c2602a9..4f81669986ba 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -107,7 +107,6 @@ struct venus_format { * @vcodec1_clks: an array of vcodec1 struct clk pointers * @video_path: an interconnect handle to video to/from memory path * @cpucfg_path: an interconnect handle to cpu configuration path - * @opp_table: an device OPP table handle * @has_opp_table: does OPP table exist * @pmdomains: an array of pmdomains struct device pointers * @opp_dl_venus: an device-link for device OPP @@ -317,6 +316,14 @@ enum venus_dec_state { VENUS_DEC_STATE_DRC = 7, }; +enum venus_enc_state { + VENUS_ENC_STATE_DEINIT = 0, + VENUS_ENC_STATE_INIT = 1, + VENUS_ENC_STATE_ENCODING = 2, + VENUS_ENC_STATE_STOPPED = 3, + VENUS_ENC_STATE_DRAIN = 4, +}; + struct venus_ts_metadata { bool used; u64 ts_ns; @@ -428,6 +435,7 @@ struct venus_inst { u8 quantization; u8 xfer_func; enum venus_dec_state codec_state; + enum venus_enc_state enc_state; wait_queue_head_t reconf_wait; unsigned int subscriptions; int buf_count; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 61ff20a7e935..cfb11c551167 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -38,8 +38,8 @@ static void venus_reset_cpu(struct venus_core *core) writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR); writel(0, wrapper_base + WRAPPER_CPA_START_ADDR); writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR); - writel(0, wrapper_base + WRAPPER_NONPIX_START_ADDR); - writel(0, wrapper_base + WRAPPER_NONPIX_END_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR); if (IS_V6(core)) { /* Bring XTSS out of reset */ diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index ab6a29ffc81e..a2ceab7f9ddb 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -988,8 +988,8 @@ static u32 get_framesize_raw_p010(u32 width, u32 height) { u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines; - y_stride = ALIGN(width * 2, 256); - uv_stride = ALIGN(width * 2, 256); + y_stride = ALIGN(width * 2, 128); + uv_stride = ALIGN(width * 2, 128); y_sclines = ALIGN(height, 32); uv_sclines = ALIGN((height + 1) >> 1, 16); y_plane = y_stride * y_sclines; diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 930b743f225e..bc3f8ff05840 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1257,7 +1257,30 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, pkt->shdr.hdr.size += sizeof(u32) + sizeof(*tm); break; } + case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2: { + struct hfi_quantization_range_v2 *in = pdata, *range = prop_data; + u32 min_qp, max_qp; + + min_qp = in->min_qp.qp_packed; + max_qp = in->max_qp.qp_packed; + /* We'll be packing in the qp, so make sure we + * won't be losing data when masking + */ + if (min_qp > 0xff || max_qp > 0xff) + return -ERANGE; + + range->min_qp.layer_id = 0xFF; + range->max_qp.layer_id = 0xFF; + range->min_qp.qp_packed = (min_qp & 0xFF) | ((min_qp & 0xFF) << 8) | + ((min_qp & 0xFF) << 16); + range->max_qp.qp_packed = (max_qp & 0xFF) | ((max_qp & 0xFF) << 8) | + ((max_qp & 0xFF) << 16); + range->min_qp.enable = 7; + range->max_qp.enable = 7; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*range); + break; + } case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index d2d6719a2ba4..105792a68060 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -487,6 +487,11 @@ #define HFI_PROPERTY_PARAM_VENC_SESSION_QP 0x2005006 #define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION 0x2005007 #define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE 0x2005008 +/* + * Note: HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 is + * specific to HFI_VERSION_6XX and HFI_VERSION_4XX only + */ +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 0x2005009 #define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION 0x2005009 #define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER 0x200500a #define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION 0x200500b @@ -827,6 +832,19 @@ struct hfi_quantization_range { u32 layer_id; }; +struct hfi_quantization_v2 { + u32 qp_packed; + u32 layer_id; + u32 enable; + u32 reserved[3]; +}; + +struct hfi_quantization_range_v2 { + struct hfi_quantization_v2 min_qp; + struct hfi_quantization_v2 max_qp; + u32 reserved[4]; +}; + #define HFI_LTR_MODE_DISABLE 0x0 #define HFI_LTR_MODE_MANUAL 0x1 #define HFI_LTR_MODE_PERIODIC 0x2 diff --git a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c index ea25c451222b..a9be31ec6927 100644 --- a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c @@ -93,7 +93,7 @@ #define LCU_MIN_SIZE_PELS 16 #define SIZE_SEI_USERDATA 4096 -#define H265D_MAX_SLICE 600 +#define H265D_MAX_SLICE 3600 #define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T #define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(u32)) #define SIZE_H265D_VPP_CMD_PER_BUF 256 @@ -1021,7 +1021,7 @@ static u32 h264d_persist1_size(void) static u32 h265d_persist1_size(void) { return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + H265_NUM_TILE - * sizeof(u32)), HFI_DMA_ALIGNMENT); + * sizeof(u32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA), HFI_DMA_ALIGNMENT); } static u32 vp8d_persist1_size(void) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 4ceaba37e2e5..51a53bf82bd3 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -31,15 +31,15 @@ */ static const struct venus_format vdec_formats[] = { { - .pixfmt = V4L2_PIX_FMT_QC08C, + .pixfmt = V4L2_PIX_FMT_NV12, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, }, { - .pixfmt = V4L2_PIX_FMT_QC10C, + .pixfmt = V4L2_PIX_FMT_QC08C, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, - },{ - .pixfmt = V4L2_PIX_FMT_NV12, + }, { + .pixfmt = V4L2_PIX_FMT_QC10C, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, }, { @@ -204,8 +204,13 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->height); if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + unsigned int stride = pixmp->width; + + if (pixmp->pixelformat == V4L2_PIX_FMT_P010) + stride *= 2; + pfmt[0].sizeimage = szimage; - pfmt[0].bytesperline = ALIGN(pixmp->width, 128); + pfmt[0].bytesperline = ALIGN(stride, 128); } else { pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M); pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage); @@ -526,6 +531,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct venus_inst *inst = to_inst(file); + struct vb2_queue *dst_vq; struct hfi_frame_data fdata = {0}; int ret; @@ -556,6 +562,13 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) inst->codec_state = VENUS_DEC_STATE_DRAIN; inst->drain_active = true; } + } else if (cmd->cmd == V4L2_DEC_CMD_START && + inst->codec_state == VENUS_DEC_STATE_STOPPED) { + dst_vq = v4l2_m2m_get_vq(inst->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + vb2_clear_last_buffer_dequeued(dst_vq); + + inst->codec_state = VENUS_DEC_STATE_DECODING; } unlock: @@ -1774,7 +1787,7 @@ err_vdev_release: return ret; } -static int vdec_remove(struct platform_device *pdev) +static void vdec_remove(struct platform_device *pdev) { struct venus_core *core = dev_get_drvdata(pdev->dev.parent); @@ -1783,8 +1796,6 @@ static int vdec_remove(struct platform_device *pdev) if (core->pm_ops->vdec_put) core->pm_ops->vdec_put(core->dev_dec); - - return 0; } static __maybe_unused int vdec_runtime_suspend(struct device *dev) @@ -1825,7 +1836,7 @@ MODULE_DEVICE_TABLE(of, vdec_dt_match); static struct platform_driver qcom_venus_dec_driver = { .probe = vdec_probe, - .remove = vdec_remove, + .remove_new = vdec_remove, .driver = { .name = "qcom-venus-decoder", .of_match_table = vdec_dt_match, diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index cdb12546c4fa..4666f42feea3 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -520,6 +520,51 @@ static int venc_subscribe_event(struct v4l2_fh *fh, } } +static int +venc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) +{ + struct venus_inst *inst = to_inst(file); + struct hfi_frame_data fdata = {0}; + int ret = 0; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); + if (ret) + return ret; + + mutex_lock(&inst->lock); + + if (cmd->cmd == V4L2_ENC_CMD_STOP && + inst->enc_state == VENUS_ENC_STATE_ENCODING) { + /* + * Implement V4L2_ENC_CMD_STOP by enqueue an empty buffer on + * encoder input to signal EOS. + */ + if (!(inst->streamon_out && inst->streamon_cap)) + goto unlock; + + fdata.buffer_type = HFI_BUFFER_INPUT; + fdata.flags |= HFI_BUFFERFLAG_EOS; + fdata.device_addr = 0xdeadb000; + + ret = hfi_session_process_buf(inst, &fdata); + + inst->enc_state = VENUS_ENC_STATE_DRAIN; + } else if (cmd->cmd == V4L2_ENC_CMD_START) { + if (inst->enc_state == VENUS_ENC_STATE_DRAIN) { + ret = -EBUSY; + goto unlock; + } + if (inst->enc_state == VENUS_ENC_STATE_STOPPED) { + vb2_clear_last_buffer_dequeued(&inst->fh.m2m_ctx->cap_q_ctx.q); + inst->enc_state = VENUS_ENC_STATE_ENCODING; + } + } + +unlock: + mutex_unlock(&inst->lock); + return ret; +} + static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_querycap = venc_querycap, .vidioc_enum_fmt_vid_cap = venc_enum_fmt, @@ -548,6 +593,7 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_subscribe_event = venc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = venc_encoder_cmd, }; static int venc_pm_get(struct venus_inst *inst) @@ -617,6 +663,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_idr_period idrp; struct hfi_quantization quant; struct hfi_quantization_range quant_range; + struct hfi_quantization_range_v2 quant_range_v2; struct hfi_enable en; struct hfi_ltr_mode ltr_mode; struct hfi_intra_refresh intra_refresh = {}; @@ -825,16 +872,40 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; - ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; - if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { - quant_range.min_qp = ctr->hevc_min_qp; - quant_range.max_qp = ctr->hevc_max_qp; + if (inst->core->res->hfi_version == HFI_VERSION_4XX || + inst->core->res->hfi_version == HFI_VERSION_6XX) { + ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2; + + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + quant_range_v2.min_qp.qp_packed = ctr->hevc_min_qp; + quant_range_v2.max_qp.qp_packed = ctr->hevc_max_qp; + } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) { + quant_range_v2.min_qp.qp_packed = ctr->vp8_min_qp; + quant_range_v2.max_qp.qp_packed = ctr->vp8_max_qp; + } else { + quant_range_v2.min_qp.qp_packed = ctr->h264_min_qp; + quant_range_v2.max_qp.qp_packed = ctr->h264_max_qp; + } + + ret = hfi_session_set_property(inst, ptype, &quant_range_v2); } else { - quant_range.min_qp = ctr->h264_min_qp; - quant_range.max_qp = ctr->h264_max_qp; + ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; + + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + quant_range.min_qp = ctr->hevc_min_qp; + quant_range.max_qp = ctr->hevc_max_qp; + } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) { + quant_range.min_qp = ctr->vp8_min_qp; + quant_range.max_qp = ctr->vp8_max_qp; + } else { + quant_range.min_qp = ctr->h264_min_qp; + quant_range.max_qp = ctr->h264_max_qp; + } + + quant_range.layer_id = 0; + ret = hfi_session_set_property(inst, ptype, &quant_range); } - quant_range.layer_id = 0; - ret = hfi_session_set_property(inst, ptype, &quant_range); + if (ret) return ret; @@ -1196,6 +1267,8 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) goto error; + inst->enc_state = VENUS_ENC_STATE_ENCODING; + mutex_unlock(&inst->lock); return 0; @@ -1215,10 +1288,21 @@ error: static void venc_vb2_buf_queue(struct vb2_buffer *vb) { struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); venc_pm_get_put(inst); mutex_lock(&inst->lock); + + if (inst->enc_state == VENUS_ENC_STATE_STOPPED) { + vbuf->sequence = inst->sequence_cap++; + vbuf->field = V4L2_FIELD_NONE; + vb2_set_plane_payload(vb, 0, 0); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + mutex_unlock(&inst->lock); + return; + } + venus_helper_vb2_buf_queue(vb); mutex_unlock(&inst->lock); } @@ -1260,6 +1344,10 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; + if ((vbuf->flags & V4L2_BUF_FLAG_LAST) && + inst->enc_state == VENUS_ENC_STATE_DRAIN) { + inst->enc_state = VENUS_ENC_STATE_STOPPED; + } } else { vbuf->sequence = inst->sequence_out++; } @@ -1362,6 +1450,9 @@ static int venc_open(struct file *file) inst->core_acquired = false; inst->nonblock = file->f_flags & O_NONBLOCK; + if (inst->enc_state == VENUS_ENC_STATE_DEINIT) + inst->enc_state = VENUS_ENC_STATE_INIT; + venus_helper_init_instance(inst); ret = venc_ctrl_init(inst); @@ -1424,6 +1515,8 @@ static int venc_close(struct file *file) v4l2_fh_del(&inst->fh); v4l2_fh_exit(&inst->fh); + inst->enc_state = VENUS_ENC_STATE_DEINIT; + venc_pm_put(inst, false); kfree(inst); @@ -1492,7 +1585,7 @@ err_vdev_release: return ret; } -static int venc_remove(struct platform_device *pdev) +static void venc_remove(struct platform_device *pdev) { struct venus_core *core = dev_get_drvdata(pdev->dev.parent); @@ -1501,8 +1594,6 @@ static int venc_remove(struct platform_device *pdev) if (core->pm_ops->venc_put) core->pm_ops->venc_put(core->dev_enc); - - return 0; } static __maybe_unused int venc_runtime_suspend(struct device *dev) @@ -1543,7 +1634,7 @@ MODULE_DEVICE_TABLE(of, venc_dt_match); static struct platform_driver qcom_venus_enc_driver = { .probe = venc_probe, - .remove = venc_remove, + .remove_new = venc_remove, .driver = { .name = "qcom-venus-encoder", .of_match_table = venc_dt_match, |