Merge "msm: vidc: Add support for decoder downscaling"
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 ca17390..f9b5519 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2365,6 +2365,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);
@@ -2391,9 +2392,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 f2f0f5d..6ed94e4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1098,6 +1098,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;
@@ -1204,6 +1205,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 03788e4..42460fa 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;
@@ -559,8 +574,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) {
@@ -658,13 +678,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");
@@ -988,12 +1046,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");
@@ -1001,8 +1102,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;
@@ -1838,6 +1949,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)
{
@@ -2228,7 +2443,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) &&
@@ -2322,6 +2538,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)
{
@@ -2496,6 +2768,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;
@@ -2710,6 +3002,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
@@ -2886,8 +3183,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 05d1840..cc07806 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)