summaryrefslogtreecommitdiff
path: root/drivers/media/platform/qcom/venus/venc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/qcom/venus/venc.c')
-rw-r--r--drivers/media/platform/qcom/venus/venc.c227
1 files changed, 135 insertions, 92 deletions
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 6b2ce479584e..41249d1443fa 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -14,6 +14,7 @@
*/
#include <linux/clk.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
@@ -24,38 +25,13 @@
#include <media/v4l2-ctrls.h>
#include "hfi_venus_io.h"
+#include "hfi_parser.h"
#include "core.h"
#include "helpers.h"
#include "venc.h"
#define NUM_B_FRAMES_MAX 4
-static u32 get_framesize_uncompressed(unsigned int plane, u32 width, u32 height)
-{
- u32 y_stride, uv_stride, y_plane;
- u32 y_sclines, uv_sclines, uv_plane;
- u32 size;
-
- y_stride = ALIGN(width, 128);
- uv_stride = ALIGN(width, 128);
- y_sclines = ALIGN(height, 32);
- uv_sclines = ALIGN(((height + 1) >> 1), 16);
-
- y_plane = y_stride * y_sclines;
- uv_plane = uv_stride * uv_sclines + SZ_4K;
- size = y_plane + uv_plane + SZ_8K;
- size = ALIGN(size, SZ_4K);
-
- return size;
-}
-
-static u32 get_framesize_compressed(u32 width, u32 height)
-{
- u32 sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2 / 2;
-
- return ALIGN(sz, SZ_4K);
-}
-
/*
* Three resons to keep MPLANE formats (despite that the number of planes
* currently is one):
@@ -84,6 +60,10 @@ static const struct venus_format venc_formats[] = {
.pixfmt = V4L2_PIX_FMT_VP8,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ }, {
+ .pixfmt = V4L2_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
},
};
@@ -223,7 +203,7 @@ static int venc_v4l2_to_hfi(int id, int value)
case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
return HFI_H264_ENTROPY_CABAC;
}
- case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
switch (value) {
case 0:
default:
@@ -245,6 +225,46 @@ static int venc_v4l2_to_hfi(int id, int value)
case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
}
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
+ default:
+ return HFI_HEVC_PROFILE_MAIN;
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
+ return HFI_HEVC_PROFILE_MAIN_STILL_PIC;
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
+ return HFI_HEVC_PROFILE_MAIN10;
+ }
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
+ default:
+ return HFI_HEVC_LEVEL_1;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
+ return HFI_HEVC_LEVEL_2;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
+ return HFI_HEVC_LEVEL_21;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
+ return HFI_HEVC_LEVEL_3;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
+ return HFI_HEVC_LEVEL_31;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
+ return HFI_HEVC_LEVEL_4;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
+ return HFI_HEVC_LEVEL_41;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
+ return HFI_HEVC_LEVEL_5;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
+ return HFI_HEVC_LEVEL_51;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
+ return HFI_HEVC_LEVEL_52;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_6:
+ return HFI_HEVC_LEVEL_6;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1:
+ return HFI_HEVC_LEVEL_61;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2:
+ return HFI_HEVC_LEVEL_62;
+ }
}
return 0;
@@ -283,7 +303,6 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
const struct venus_format *fmt;
- unsigned int p;
memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
@@ -297,14 +316,12 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
else
return NULL;
fmt = find_format(inst, pixmp->pixelformat, f->type);
- pixmp->width = 1280;
- pixmp->height = 720;
}
- pixmp->width = clamp(pixmp->width, inst->cap_width.min,
- inst->cap_width.max);
- pixmp->height = clamp(pixmp->height, inst->cap_height.min,
- inst->cap_height.max);
+ pixmp->width = clamp(pixmp->width, frame_width_min(inst),
+ frame_width_max(inst));
+ pixmp->height = clamp(pixmp->height, frame_height_min(inst),
+ frame_height_max(inst));
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
pixmp->height = ALIGN(pixmp->height, 32);
@@ -317,19 +334,14 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
pixmp->num_planes = fmt->num_planes;
pixmp->flags = 0;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- for (p = 0; p < pixmp->num_planes; p++) {
- pfmt[p].sizeimage =
- get_framesize_uncompressed(p, pixmp->width,
- pixmp->height);
+ pfmt[0].sizeimage = venus_helper_get_framesz(pixmp->pixelformat,
+ pixmp->width,
+ pixmp->height);
- pfmt[p].bytesperline = ALIGN(pixmp->width, 128);
- }
- } else {
- pfmt[0].sizeimage = get_framesize_compressed(pixmp->width,
- pixmp->height);
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ pfmt[0].bytesperline = ALIGN(pixmp->width, 128);
+ else
pfmt[0].bytesperline = 0;
- }
return fmt;
}
@@ -553,12 +565,12 @@ static int venc_enum_framesizes(struct file *file, void *fh,
if (fsize->index)
return -EINVAL;
- fsize->stepwise.min_width = inst->cap_width.min;
- fsize->stepwise.max_width = inst->cap_width.max;
- fsize->stepwise.step_width = inst->cap_width.step_size;
- fsize->stepwise.min_height = inst->cap_height.min;
- fsize->stepwise.max_height = inst->cap_height.max;
- fsize->stepwise.step_height = inst->cap_height.step_size;
+ fsize->stepwise.min_width = frame_width_min(inst);
+ fsize->stepwise.max_width = frame_width_max(inst);
+ fsize->stepwise.step_width = frame_width_step(inst);
+ fsize->stepwise.min_height = frame_height_min(inst);
+ fsize->stepwise.max_height = frame_height_max(inst);
+ fsize->stepwise.step_height = frame_height_step(inst);
return 0;
}
@@ -586,18 +598,18 @@ static int venc_enum_frameintervals(struct file *file, void *fh,
if (!fival->width || !fival->height)
return -EINVAL;
- if (fival->width > inst->cap_width.max ||
- fival->width < inst->cap_width.min ||
- fival->height > inst->cap_height.max ||
- fival->height < inst->cap_height.min)
+ if (fival->width > frame_width_max(inst) ||
+ fival->width < frame_width_min(inst) ||
+ fival->height > frame_height_max(inst) ||
+ fival->height < frame_height_min(inst))
return -EINVAL;
fival->stepwise.min.numerator = 1;
- fival->stepwise.min.denominator = inst->cap_framerate.max;
+ fival->stepwise.min.denominator = frate_max(inst);
fival->stepwise.max.numerator = 1;
- fival->stepwise.max.denominator = inst->cap_framerate.min;
+ fival->stepwise.max.denominator = frate_min(inst);
fival->stepwise.step.numerator = 1;
- fival->stepwise.step.denominator = inst->cap_framerate.max;
+ fival->stepwise.step.denominator = frate_max(inst);
return 0;
}
@@ -642,6 +654,14 @@ static int venc_set_properties(struct venus_inst *inst)
u32 ptype, rate_control, bitrate, profile = 0, level = 0;
int ret;
+ ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2);
+ if (ret)
+ return ret;
+
+ ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_2);
+ if (ret)
+ return ret;
+
ptype = HFI_PROPERTY_CONFIG_FRAME_RATE;
frate.buffer_type = HFI_BUFFER_OUTPUT;
frate.framerate = inst->fps * (1 << 16);
@@ -756,7 +776,7 @@ static int venc_set_properties(struct venus_inst *inst)
level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_LEVEL,
ctr->level.h264);
} else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) {
- profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_VPX_PROFILE,
+ profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
ctr->profile.vpx);
level = 0;
} else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_MPEG4) {
@@ -767,6 +787,11 @@ static int venc_set_properties(struct venus_inst *inst)
} else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H263) {
profile = 0;
level = 0;
+ } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
+ profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ ctr->profile.hevc);
+ level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ ctr->level.hevc);
}
ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
@@ -794,7 +819,8 @@ static int venc_init_session(struct venus_inst *inst)
goto deinit;
ret = venus_helper_set_output_resolution(inst, inst->width,
- inst->height);
+ inst->height,
+ HFI_BUFFER_OUTPUT);
if (ret)
goto deinit;
@@ -835,7 +861,7 @@ static int venc_queue_setup(struct vb2_queue *q,
unsigned int sizes[], struct device *alloc_devs[])
{
struct venus_inst *inst = vb2_get_drv_priv(q);
- unsigned int p, num, min = 4;
+ unsigned int num, min = 4;
int ret = 0;
if (*num_planes) {
@@ -870,16 +896,18 @@ static int venc_queue_setup(struct vb2_queue *q,
*num_buffers = max(*num_buffers, num);
inst->num_input_bufs = *num_buffers;
- for (p = 0; p < *num_planes; ++p)
- sizes[p] = get_framesize_uncompressed(p, inst->width,
- inst->height);
+ sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt,
+ inst->width,
+ inst->height);
inst->input_buf_size = sizes[0];
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
*num_planes = inst->fmt_cap->num_planes;
*num_buffers = max(*num_buffers, min);
inst->num_output_bufs = *num_buffers;
- sizes[0] = get_framesize_compressed(inst->width, inst->height);
+ sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt,
+ inst->width,
+ inst->height);
inst->output_buf_size = sizes[0];
break;
default:
@@ -892,6 +920,7 @@ static int venc_queue_setup(struct vb2_queue *q,
static int venc_verify_conf(struct venus_inst *inst)
{
+ enum hfi_version ver = inst->core->res->hfi_version;
struct hfi_buffer_requirements bufreq;
int ret;
@@ -903,7 +932,7 @@ static int venc_verify_conf(struct venus_inst *inst)
return ret;
if (inst->num_output_bufs < bufreq.count_actual ||
- inst->num_output_bufs < bufreq.count_min)
+ inst->num_output_bufs < HFI_BUFREQ_COUNT_MIN(&bufreq, ver))
return -EINVAL;
ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
@@ -911,7 +940,7 @@ static int venc_verify_conf(struct venus_inst *inst)
return ret;
if (inst->num_input_bufs < bufreq.count_actual ||
- inst->num_input_bufs < bufreq.count_min)
+ inst->num_input_bufs < HFI_BUFREQ_COUNT_MIN(&bufreq, ver))
return -EINVAL;
return 0;
@@ -952,7 +981,7 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
goto deinit_sess;
ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
- inst->num_output_bufs);
+ inst->num_output_bufs, 0);
if (ret)
goto deinit_sess;
@@ -1090,22 +1119,7 @@ static void venc_inst_init(struct venus_inst *inst)
inst->fps = 15;
inst->timeperframe.numerator = 1;
inst->timeperframe.denominator = 15;
-
- inst->cap_width.min = 96;
- inst->cap_width.max = 1920;
- if (inst->core->res->hfi_version == HFI_VERSION_3XX)
- inst->cap_width.max = 3840;
- inst->cap_width.step_size = 2;
- inst->cap_height.min = 64;
- inst->cap_height.max = ALIGN(1080, 32);
- if (inst->core->res->hfi_version == HFI_VERSION_3XX)
- inst->cap_height.max = ALIGN(2160, 32);
- inst->cap_height.step_size = 2;
- inst->cap_framerate.min = 1;
- inst->cap_framerate.max = 30;
- inst->cap_framerate.step_size = 1;
- inst->cap_mbs_per_frame.min = 24;
- inst->cap_mbs_per_frame.max = 8160;
+ inst->hfi_codec = HFI_VIDEO_CODEC_H264;
}
static int venc_open(struct file *file)
@@ -1118,6 +1132,7 @@ static int venc_open(struct file *file)
if (!inst)
return -ENOMEM;
+ INIT_LIST_HEAD(&inst->dpbbufs);
INIT_LIST_HEAD(&inst->registeredbufs);
INIT_LIST_HEAD(&inst->internalbufs);
INIT_LIST_HEAD(&inst->list);
@@ -1224,12 +1239,18 @@ static int venc_probe(struct platform_device *pdev)
if (!core)
return -EPROBE_DEFER;
- if (core->res->hfi_version == HFI_VERSION_3XX) {
+ if (IS_V3(core) || IS_V4(core)) {
core->core1_clk = devm_clk_get(dev, "core");
if (IS_ERR(core->core1_clk))
return PTR_ERR(core->core1_clk);
}
+ if (IS_V4(core)) {
+ core->core1_bus_clk = devm_clk_get(dev, "bus");
+ if (IS_ERR(core->core1_bus_clk))
+ return PTR_ERR(core->core1_bus_clk);
+ }
+
platform_set_drvdata(pdev, core);
vdev = video_device_alloc();
@@ -1274,15 +1295,21 @@ static int venc_remove(struct platform_device *pdev)
static __maybe_unused int venc_runtime_suspend(struct device *dev)
{
struct venus_core *core = dev_get_drvdata(dev);
+ int ret;
- if (core->res->hfi_version == HFI_VERSION_1XX)
+ if (IS_V1(core))
return 0;
- writel(0, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
+ ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true);
+ if (ret)
+ return ret;
+
+ if (IS_V4(core))
+ clk_disable_unprepare(core->core1_bus_clk);
+
clk_disable_unprepare(core->core1_clk);
- writel(1, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
- return 0;
+ return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
}
static __maybe_unused int venc_runtime_resume(struct device *dev)
@@ -1290,13 +1317,29 @@ static __maybe_unused int venc_runtime_resume(struct device *dev)
struct venus_core *core = dev_get_drvdata(dev);
int ret;
- if (core->res->hfi_version == HFI_VERSION_1XX)
+ if (IS_V1(core))
return 0;
- writel(0, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
+ ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true);
+ if (ret)
+ return ret;
+
ret = clk_prepare_enable(core->core1_clk);
- writel(1, core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL);
+ if (ret)
+ goto err_power_disable;
+
+ if (IS_V4(core))
+ ret = clk_prepare_enable(core->core1_bus_clk);
+
+ if (ret)
+ goto err_unprepare_core1;
+
+ return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
+err_unprepare_core1:
+ clk_disable_unprepare(core->core1_clk);
+err_power_disable:
+ venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
return ret;
}