msm: vidc: Add support for decoder downscaling
Venus FW supports downscaling for decoder. Venus
FW sends the supported downscaled ratios. Driver
needs to make sure that the scaling is inside the
supported range. This change adds support for decoder
downscaling.
Change-Id: I919e563a6ba64751b3355658bcdbcec9d9ef17eb
Signed-off-by: Praneeth Paladugu <ppaladug@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index d33a085..30ada3e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -275,12 +275,18 @@
case HAL_BUFFER_OUTPUT:
buffer = HFI_BUFFER_OUTPUT;
break;
+ case HAL_BUFFER_OUTPUT2:
+ buffer = HFI_BUFFER_OUTPUT2;
+ break;
case HAL_BUFFER_EXTRADATA_INPUT:
buffer = HFI_BUFFER_EXTRADATA_INPUT;
break;
case HAL_BUFFER_EXTRADATA_OUTPUT:
buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
break;
+ case HAL_BUFFER_EXTRADATA_OUTPUT2:
+ buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+ break;
case HAL_BUFFER_INTERNAL_SCRATCH:
buffer = HFI_BUFFER_INTERNAL_SCRATCH;
break;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 101b148..abdb039 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -957,6 +957,7 @@
data_done.output_done.packet_buffer1 = pkt->packet_buffer;
data_done.output_done.extra_data_buffer =
pkt->extra_data_buffer;
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
pkt->packet_buffer, pkt->filled_len);
} else if (is_decoder == 1) {
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 4425909..dc384bc 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -31,16 +31,16 @@
enum hal_buffer {
HAL_BUFFER_INPUT = 0x1,
HAL_BUFFER_OUTPUT = 0x2,
- HAL_BUFFER_OUTPUT2 = 0x2,
- HAL_BUFFER_EXTRADATA_INPUT = 0x4,
- HAL_BUFFER_EXTRADATA_OUTPUT = 0x8,
- HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x8,
- HAL_BUFFER_INTERNAL_SCRATCH = 0x10,
- HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x20,
- HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x40,
- HAL_BUFFER_INTERNAL_PERSIST = 0x80,
- HAL_BUFFER_INTERNAL_PERSIST_1 = 0x100,
- HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x200,
+ HAL_BUFFER_OUTPUT2 = 0x4,
+ HAL_BUFFER_EXTRADATA_INPUT = 0x8,
+ HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
+ HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
+ HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
+ HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
+ HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
+ HAL_BUFFER_INTERNAL_PERSIST = 0x200,
+ HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
};
struct msm_smem {
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 3582d78..f4fdfe7 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -307,6 +307,22 @@
.qmenu = NULL,
.cluster = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
+ .name = "Video decoder multi stream",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ .maximum =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
+ .default_value =
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .step = 1,
+ .qmenu = NULL,
+ .cluster = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -496,7 +512,8 @@
b->m.planes[i].length);
}
buffer_info.buffer_size = b->m.planes[0].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
b->m.planes[0].m.userptr;
@@ -580,7 +597,8 @@
b->m.planes[i].length);
}
buffer_info.buffer_size = b->m.planes[0].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
b->m.planes[0].m.userptr;
@@ -668,7 +686,6 @@
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
- struct hal_frame_size frame_sz;
struct hfi_device *hdev;
int stride, scanlines;
int extra_idx = 0;
@@ -690,8 +707,22 @@
f->fmt.pix_mp.pixelformat = fmt->fourcc;
f->fmt.pix_mp.num_planes = fmt->num_planes;
if (inst->in_reconfig == true) {
- inst->prop.height[CAPTURE_PORT] = inst->reconfig_height;
- inst->prop.width[CAPTURE_PORT] = inst->reconfig_width;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.height[CAPTURE_PORT] =
+ inst->reconfig_height;
+ inst->prop.width[CAPTURE_PORT] =
+ inst->reconfig_width;
+ inst->prop.height[OUTPUT_PORT] =
+ inst->reconfig_height;
+ inst->prop.width[OUTPUT_PORT] =
+ inst->reconfig_width;
+ } else {
+ inst->prop.height[OUTPUT_PORT] =
+ inst->reconfig_height;
+ inst->prop.width[OUTPUT_PORT] =
+ inst->reconfig_width;
+ }
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -703,11 +734,6 @@
f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
stride = inst->prop.width[CAPTURE_PORT];
scanlines = inst->prop.height[CAPTURE_PORT];
- frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- frame_sz.width = inst->prop.width[CAPTURE_PORT];
- frame_sz.height = inst->prop.height[CAPTURE_PORT];
- dprintk(VIDC_DBG, "width = %d, height = %d\n",
- frame_sz.width, frame_sz.height);
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -733,7 +759,8 @@
"Color format not recognized\n");
}
buff_req_buffer =
- get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
if (buff_req_buffer)
f->fmt.pix_mp.plane_fmt[0].sizeimage =
buff_req_buffer->buffer_size;
@@ -855,9 +882,24 @@
}
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
- inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
- inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ }
inst->fmts[fmt->type] = fmt;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
+ dprintk(VIDC_DBG,
+ "buffer type = %d width = %d, height = %d\n",
+ frame_sz.buffer_type, frame_sz.width,
+ frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ }
ret = ret || msm_comm_try_get_bufreqs(inst);
if (ret) {
for (i = 0; i < fmt->num_planes; ++i) {
@@ -868,7 +910,8 @@
}
} else {
buff_req_buffer =
- get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
if (buff_req_buffer)
f->fmt.pix_mp.plane_fmt[0].sizeimage =
buff_req_buffer->buffer_size;
@@ -895,8 +938,11 @@
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
- inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
- inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_PRIMARY) {
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ }
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -923,6 +969,10 @@
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width[OUTPUT_PORT];
frame_sz.height = inst->prop.height[OUTPUT_PORT];
+ dprintk(VIDC_DBG,
+ "buffer type = %d width = %d, height = %d\n",
+ frame_sz.buffer_type, frame_sz.width,
+ frame_sz.height);
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
max_input_size = fmt->get_frame_size(0,
@@ -1055,7 +1105,8 @@
break;
}
mutex_lock(&inst->lock);
- bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ bufreq = get_buff_req_buffer(inst,
+ msm_comm_get_hal_output_buffer(inst));
if (!bufreq) {
dprintk(VIDC_ERR,
"No buffer requirement for buffer type %x\n",
@@ -1067,7 +1118,8 @@
*num_buffers = max(*num_buffers, bufreq->buffer_count_min);
if (*num_buffers != bufreq->buffer_count_actual) {
property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
- new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
new_buf_count.buffer_count_actual = *num_buffers;
rc = call_hfi_op(hdev, session_set_property,
inst->session, property_id, &new_buf_count);
@@ -1097,14 +1149,75 @@
return rc;
}
+static int msm_vdec_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct internal_buf *binfo;
+ struct hfi_device *hdev;
+ struct msm_smem *handle;
+ struct vidc_frame_data frame_data = {0};
+ struct hal_buffer_requirements *output_buf, *extradata_buf;
+ int rc = 0;
+ hdev = inst->core->device;
+
+ output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_OUTPUT);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "output: num = %d, size = %d\n",
+ output_buf->buffer_count_actual,
+ output_buf->buffer_size);
+
+ extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (!extradata_buf) {
+ dprintk(VIDC_DBG,
+ "This extradata buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ return 0;
+ }
+
+ hdev = inst->core->device;
+
+ mutex_lock(&inst->lock);
+ if (!list_empty(&inst->outputbufs)) {
+ list_for_each_entry(binfo, &inst->outputbufs, list) {
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Invalid parameter\n");
+ mutex_unlock(&inst->lock);
+ return -EINVAL;
+ }
+ handle = binfo->handle;
+ frame_data.alloc_len = output_buf->buffer_size;
+ frame_data.filled_len = 0;
+ frame_data.offset = 0;
+ frame_data.device_addr = handle->device_addr;
+ frame_data.flags = 0;
+ frame_data.extradata_addr = handle->device_addr +
+ output_buf->buffer_size;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = call_hfi_op(hdev, session_ftb,
+ (void *) inst->session, &frame_data);
+ binfo->buffer_ownership = FIRMWARE;
+ }
+ }
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
struct vb2_buf_entry *temp;
+ struct hfi_device *hdev;
struct list_head *ptr, *next;
+
+ hdev = inst->core->device;
inst->in_reconfig = false;
- if (inst->capability.pixelprocess_capabilities &
- HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY)
rc = msm_comm_check_scaling_supported(inst);
if (rc) {
dprintk(VIDC_ERR, "H/w scaling is not in valid range");
@@ -1123,6 +1236,15 @@
goto fail_start;
}
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ rc = msm_comm_set_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set output buffers: %d\n", rc);
+ goto fail_start;
+ }
+ }
mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
mutex_unlock(&inst->core->sync_lock);
@@ -1133,7 +1255,15 @@
"Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
-
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ rc = msm_vdec_queue_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to queue output buffers: %d\n", rc);
+ goto fail_start;
+ }
+ }
mutex_lock(&inst->sync_lock);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
@@ -1389,6 +1519,7 @@
struct hfi_device *hdev;
struct hal_extradata_enable extra;
struct hal_buffer_alloc_mode alloc_mode;
+ struct hal_multi_stream multi_stream;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1516,7 +1647,70 @@
pdata = &alloc_mode;
inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
break;
-
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+ if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
+ dprintk(VIDC_ERR, "Downscaling not supported: 0x%x",
+ ctrl->id);
+ rc = -ENOTSUPP;
+ break;
+ }
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+ multi_stream.enable = true;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed : Enabling OUTPUT port : %d\n",
+ rc);
+ break;
+ }
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+ multi_stream.enable = false;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed:Disabling OUTPUT2 port : %d\n",
+ rc);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+ multi_stream.enable = true;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed :Enabling OUTPUT2 port : %d\n",
+ rc);
+ break;
+ }
+ multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+ multi_stream.enable = false;
+ pdata = &multi_stream;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+ pdata);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed :Disabling OUTPUT port : %d\n",
+ rc);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Failed : Unsupported multi stream setting\n");
+ rc = -ENOTSUPP;
+ break;
+ }
+ break;
default:
break;
}
@@ -1537,6 +1731,10 @@
int rc = 0, c = 0;
struct msm_vidc_inst *inst = container_of(ctrl->handler,
struct msm_vidc_inst, ctrl_handler);
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 975f98b..6592125 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2355,6 +2355,7 @@
int i;
u32 height, width;
int extra_idx = 0;
+ struct hal_buffer_requirements *buff_req_buffer;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -2381,9 +2382,12 @@
}
extra_idx = EXTRADATA_IDX(fmt->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buff_req_buffer =
+ get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
- inst->buff_req.buffer
- [HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ buff_req_buffer ?
+ buff_req_buffer->buffer_size : 0;
}
for (i = 0; i < fmt->num_planes; ++i) {
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 89fbc2a..1969bb3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1096,6 +1096,7 @@
INIT_LIST_HEAD(&inst->persistbufs);
INIT_LIST_HEAD(&inst->ctrl_clusters);
INIT_LIST_HEAD(&inst->registered_bufs);
+ INIT_LIST_HEAD(&inst->outputbufs);
init_waitqueue_head(&inst->kernel_event_queue);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
@@ -1202,6 +1203,17 @@
mutex_lock(&inst->lock);
}
}
+ if (!list_empty(&inst->outputbufs)) {
+ list_for_each_safe(ptr, next, &inst->outputbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&buf->list);
+ mutex_unlock(&inst->lock);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ mutex_lock(&inst->lock);
+ }
+ }
if (inst->extradata_handle) {
mutex_unlock(&inst->lock);
msm_smem_free(inst->mem_client, inst->extradata_handle);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 6da90c4..7f4503f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -82,6 +82,21 @@
}
return false;
}
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ int rc = 0;
+ struct v4l2_control ctrl = {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE
+ };
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl);
+ if (!rc && ctrl.value)
+ return HAL_VIDEO_DECODER_SECONDARY;
+ }
+ return HAL_VIDEO_DECODER_PRIMARY;
+
+
+}
static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
{
int height, width;
@@ -557,8 +572,13 @@
"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
inst->prop.height[CAPTURE_PORT] = event_notify->height;
inst->prop.width[CAPTURE_PORT] = event_notify->width;
- inst->prop.height[OUTPUT_PORT] = event_notify->height;
- inst->prop.width[OUTPUT_PORT] = event_notify->width;
+ if (!msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ inst->prop.height[OUTPUT_PORT] =
+ event_notify->height;
+ inst->prop.width[OUTPUT_PORT] =
+ event_notify->width;
+ }
}
rc = msm_vidc_check_session_supported(inst);
if (!rc) {
@@ -656,13 +676,51 @@
"Failed to get valid response for release resource\n");
}
}
+void validate_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct internal_buf *binfo;
+ u32 buffers_owned_by_driver = 0;
+ struct hal_buffer_requirements *output_buf;
+ output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_OUTPUT);
+ return;
+ }
+ list_for_each_entry(binfo, &inst->outputbufs, list) {
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Invalid parameter\n");
+ return;
+ }
+ if (binfo->buffer_ownership != DRIVER) {
+ dprintk(VIDC_ERR,
+ "Failed : This buffer is with FW 0x%lx\n",
+ binfo->handle->device_addr);
+ return;
+ }
+ buffers_owned_by_driver++;
+ }
+ if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+ dprintk(VIDC_ERR,
+ "OUTPUT Buffer count mismatch %d of %d",
+ buffers_owned_by_driver,
+ output_buf->buffer_count_actual);
+ return;
+}
static void handle_session_flush(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ mutex_lock(&inst->lock);
+ validate_output_buffers(inst);
+ mutex_unlock(&inst->lock);
+ }
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
} else {
dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
@@ -986,12 +1044,55 @@
}
}
+static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
+ u32 dev_addr)
+{
+ struct internal_buf *binfo;
+ struct msm_smem *handle;
+ bool found = false;
+ mutex_lock(&inst->lock);
+ list_for_each_entry(binfo, &inst->outputbufs, list) {
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Invalid parameter\n");
+ break;
+ }
+ handle = binfo->handle;
+ if (handle && dev_addr == handle->device_addr) {
+ if (binfo->buffer_ownership == DRIVER) {
+ dprintk(VIDC_ERR,
+ "FW returned same buffer : 0x%x\n",
+ dev_addr);
+ break;
+ }
+ binfo->buffer_ownership = DRIVER;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ dprintk(VIDC_ERR,
+ "Failed to find output buffer in queued list: 0x%x\n",
+ dev_addr);
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
+{
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY)
+ return HAL_BUFFER_OUTPUT2;
+ else
+ return HAL_BUFFER_OUTPUT;
+}
+
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
struct msm_vidc_inst *inst;
- struct vb2_buffer *vb;
+ struct vb2_buffer *vb = NULL;
struct vidc_hal_fbd *fill_buf_done;
+ enum hal_buffer buffer_type;
if (!response) {
dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -999,8 +1100,18 @@
}
inst = (struct msm_vidc_inst *)response->session_id;
fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
- vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
- (u32)fill_buf_done->packet_buffer1);
+ buffer_type = msm_comm_get_hal_output_buffer(inst);
+ if (fill_buf_done->buffer_type == buffer_type)
+ vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+ (u32)fill_buf_done->packet_buffer1);
+ else {
+ if (handle_multi_stream_buffers(inst,
+ (u32)fill_buf_done->packet_buffer1))
+ dprintk(VIDC_ERR,
+ "Failed : Output buffer not found 0x%x\n",
+ (u32)fill_buf_done->packet_buffer1);
+ return;
+ }
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
@@ -1836,6 +1947,110 @@
return NULL;
}
+static int set_output_buffers(struct msm_vidc_inst *inst,
+ enum hal_buffer buffer_type)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ u32 smem_flags = 0, buffer_size;
+ struct hal_buffer_requirements *output_buf, *extradata_buf;
+ int i;
+ struct hfi_device *hdev;
+
+ hdev = inst->core->device;
+
+ output_buf = get_buff_req_buffer(inst, buffer_type);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ buffer_type);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "output: num = %d, size = %d\n",
+ output_buf->buffer_count_actual,
+ output_buf->buffer_size);
+
+ extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (!extradata_buf) {
+ dprintk(VIDC_DBG,
+ "This extradata buffer not required, buffer_type: %x\n",
+ buffer_type);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "extradata: num = %d, size = %d\n",
+ extradata_buf->buffer_count_actual,
+ extradata_buf->buffer_size);
+
+ buffer_size = output_buf->buffer_size + extradata_buf->buffer_size;
+ if (inst->flags & VIDC_SECURE)
+ smem_flags |= SMEM_SECURE;
+
+ if (output_buf->buffer_size) {
+ for (i = 0; i < output_buf->buffer_count_actual;
+ i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ buffer_size, 1, smem_flags,
+ buffer_type, 0);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "Failed to allocate output memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto fail_kzalloc;
+ }
+ mutex_lock(&inst->lock);
+ binfo->handle = handle;
+ buffer_info.buffer_size = output_buf->buffer_size;
+ buffer_info.buffer_type = buffer_type;
+ binfo->buffer_type = buffer_type;
+ buffer_info.num_buffers = 1;
+ binfo->buffer_ownership = DRIVER;
+ buffer_info.align_device_addr = handle->device_addr;
+ buffer_info.extradata_addr = handle->device_addr +
+ output_buf->buffer_size;
+ buffer_info.extradata_size = extradata_buf->buffer_size;
+ dprintk(VIDC_DBG, "Output buffer address: %x",
+ buffer_info.align_device_addr);
+ dprintk(VIDC_DBG, "Output extradata address: %x",
+ buffer_info.extradata_addr);
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *) inst->session, &buffer_info);
+ mutex_unlock(&inst->lock);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : session_set_buffers failed",
+ __func__);
+ goto fail_set_buffers;
+ }
+ mutex_lock(&inst->lock);
+ list_add_tail(&binfo->list, &inst->outputbufs);
+ mutex_unlock(&inst->lock);
+ }
+ }
+ return rc;
+fail_set_buffers:
+ kfree(binfo);
+fail_kzalloc:
+ msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+ return rc;
+}
+
static int set_scratch_buffers(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type)
{
@@ -2226,7 +2441,8 @@
frame_data.filled_len = 0;
frame_data.offset = 0;
frame_data.alloc_len = vb->v4l2_planes[0].length;
- frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_data.buffer_type =
+ msm_comm_get_hal_output_buffer(inst);
extra_idx =
EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
@@ -2320,6 +2536,62 @@
mutex_unlock(&inst->sync_lock);
return rc;
}
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
+ if (!inst) {
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ core = inst->core;
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Invalid core pointer = %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
+ mutex_lock(&inst->lock);
+ if (!list_empty(&inst->outputbufs)) {
+ list_for_each_safe(ptr, next, &inst->outputbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = buf->buffer_type;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ if (inst->state != MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Rel output buf fail:0x%x, %d",
+ buffer_info.align_device_addr,
+ buffer_info.buffer_size);
+ }
+ list_del(&buf->list);
+ mutex_unlock(&inst->lock);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ mutex_lock(&inst->lock);
+ }
+ }
+ mutex_unlock(&inst->lock);
+ return rc;
+}
int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
{
@@ -2494,6 +2766,26 @@
return rc;
}
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_comm_release_output_buffers(inst))
+ dprintk(VIDC_WARN, "Failed to release output buffers\n");
+
+ rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
+ if (rc)
+ goto error;
+ return rc;
+error:
+ msm_comm_release_output_buffers(inst);
+ return rc;
+}
+
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -2704,6 +2996,11 @@
}
rc = call_hfi_op(hdev, session_flush, inst->session,
HAL_FLUSH_OUTPUT);
+ if (!rc && (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY))
+ rc = call_hfi_op(hdev, session_flush, inst->session,
+ HAL_FLUSH_OUTPUT2);
+
} else {
if (!list_empty(&inst->pendingq)) {
/*If flush is called after queueing buffers but before
@@ -2882,8 +3179,8 @@
u32 input_height, input_width, output_height, output_width;
if (!inst->capability.scale_x.min || !inst->capability.scale_x.max ||
- !inst->capability.scale_y.min ||
- !inst->capability.scale_y.max) {
+ !inst->capability.scale_y.min ||
+ !inst->capability.scale_y.max) {
dprintk(VIDC_ERR, "%s : Invalid scaling ratios",
__func__);
return -ENOTSUPP;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 6ee773a..195fa7e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -31,6 +31,7 @@
enum hal_property ptype, void *pdata);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
@@ -46,7 +47,10 @@
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
+
int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst);
int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 3f607e9..2b1471c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -100,10 +100,18 @@
struct vb2_buffer *buf;
};
+enum buffer_owner {
+ DRIVER,
+ FIRMWARE,
+ CLIENT,
+ MAX_OWNER
+};
+
struct internal_buf {
struct list_head list;
enum hal_buffer buffer_type;
struct msm_smem *handle;
+ enum buffer_owner buffer_ownership;
};
struct msm_vidc_format {
@@ -214,6 +222,7 @@
struct list_head pendingq;
struct list_head internalbufs;
struct list_head persistbufs;
+ struct list_head outputbufs;
struct buffer_requirements buff_req;
void *mem_client;
struct v4l2_ctrl_handler ctrl_handler;
@@ -232,6 +241,7 @@
struct msm_vidc_debug debug;
struct buf_count count;
enum msm_vidc_modes flags;
+ u32 multi_stream_mode;
struct msm_vidc_core_capability capability;
enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
struct list_head registered_bufs;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 9c9506e..b2fd9ee 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -186,6 +186,14 @@
HAL_UNUSED_DOMAIN = 0x10000000,
};
+enum multi_stream {
+ HAL_VIDEO_DECODER_NONE = 0x00000000,
+ HAL_VIDEO_DECODER_PRIMARY = 0x00000001,
+ HAL_VIDEO_DECODER_SECONDARY = 0x00000002,
+ HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004,
+ HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000,
+};
+
enum hal_core_capabilities {
HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001,
HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002,
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index e6804e1..7e4ceb3 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -813,6 +813,11 @@
*min = 0;
*max = *step = 1;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index db508fe..560accb 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1897,6 +1897,12 @@
V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 35)
+enum v4l2_mpeg_vidc_video_decoder_multi_stream {
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)