Merge "ARM: dts: msm: add support for MSM8974Pro-AC boards which use PM8941+PM8841"
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 1f04e76..d32dc4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
*
* amrnb audio decoder device
*
- * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
*
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 743eee2..0eca74d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -2,7 +2,7 @@
*
* amrnb encoder device
*
- * Copyright (c) 2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -742,6 +742,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 83a2633..cfda4b9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
*
* qcelp audio input device
*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -732,6 +732,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index ae63f0d..f7295b7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -644,6 +644,7 @@
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
mutex_lock(&audio->dsp_lock);
stats.byte_count = audio->byte_count;
stats.sample_count = audio->frame_count;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 8e66939..cb3c3ea 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -503,6 +503,7 @@
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 0f8956f..37a6726 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -778,6 +778,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
index c6bddb8..288e1dc 100644
--- a/arch/arm/mach-msm/qdsp6/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -141,6 +141,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = 2;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 888cd5e..53bbe20 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1035,56 +1035,64 @@
msm_soc_device = soc_device_to_device(soc_dev);
populate_soc_sysfs_files(msm_soc_device);
+
err = sysdev_class_register(&soc_sysdev_class);
if (err) {
pr_err("%s: sysdev_class_register fail (%d)\n",
__func__, err);
- return err;
+ goto socinfo_init_err;
}
+
err = sysdev_register(&soc_sys_device);
if (err) {
pr_err("%s: sysdev_register fail (%d)\n",
__func__, err);
- return err;
+ goto socinfo_init_err;
}
+
socinfo_create_files(&soc_sys_device, socinfo_v1_files,
ARRAY_SIZE(socinfo_v1_files));
if (socinfo->v1.format < 2)
- return err;
+ goto socinfo_init_err;
+
socinfo_create_files(&soc_sys_device, socinfo_v2_files,
ARRAY_SIZE(socinfo_v2_files));
if (socinfo->v1.format < 3)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v3_files,
ARRAY_SIZE(socinfo_v3_files));
if (socinfo->v1.format < 4)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v4_files,
ARRAY_SIZE(socinfo_v4_files));
if (socinfo->v1.format < 5)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v5_files,
ARRAY_SIZE(socinfo_v5_files));
if (socinfo->v1.format < 6)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v6_files,
ARRAY_SIZE(socinfo_v6_files));
if (socinfo->v1.format < 7)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v7_files,
ARRAY_SIZE(socinfo_v7_files));
return 0;
+
+socinfo_init_err:
+ kfree(soc_dev_attr);
+ return err;
}
arch_initcall(socinfo_init_sysdev);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1dba2b6..e982feb 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -371,6 +371,9 @@
case HAL_BUFFER_MODE_RING:
buf_mode = HFI_BUFFER_MODE_RING;
break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+ break;
default:
dprintk(VIDC_ERR, "Invalid buffer mode :0x%x\n",
hal_buf_mode);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 3f89d8b..2bd038d 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -163,6 +163,38 @@
callback(VIDC_EVENT_CHANGE, &cmd_done);
}
+static void hfi_process_evt_release_buffer_ref(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct msm_vidc_cb_event event_notify = {0};
+
+ struct hfi_msg_release_buffer_ref_event_packet *data;
+
+ dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY - release_buffer_reference");
+ if (sizeof(struct hfi_msg_event_notify_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
+ return;
+ }
+
+ data = (struct hfi_msg_release_buffer_ref_event_packet *)
+ pkt->rg_ext_event_data;
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+ session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.size = sizeof(struct msm_vidc_cb_event);
+
+ event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+ event_notify.packet_buffer = data->packet_buffer;
+ event_notify.exra_data_buffer = data->exra_data_buffer;
+ cmd_done.data = &event_notify;
+ callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
static void hfi_process_sys_error(
msm_vidc_callback callback, u32 device_id)
{
@@ -229,6 +261,10 @@
case HFI_EVENT_SESSION_PROPERTY_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
break;
+ case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+ dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n");
+ hfi_process_evt_release_buffer_ref(callback, device_id, pkt);
+ break;
default:
dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
break;
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index afd7200..81afd5c 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -27,7 +27,6 @@
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
-#include "msm_smem.h"
#include "vidc_hfi_api.h"
#include "msm_vidc_resources.h"
#include "msm_vidc_res_parse.h"
@@ -38,258 +37,44 @@
uint32_t msm_vidc_pwr_collapse_delay = 2000;
-struct buffer_info {
- struct list_head list;
- int type;
- int num_planes;
- int fd[VIDEO_MAX_PLANES];
- int buff_off[VIDEO_MAX_PLANES];
- int size[VIDEO_MAX_PLANES];
- u32 uvaddr[VIDEO_MAX_PLANES];
- u32 device_addr[VIDEO_MAX_PLANES];
- struct msm_smem *handle[VIDEO_MAX_PLANES];
-};
-
-struct msm_v4l2_vid_inst {
- struct msm_vidc_inst *vidc_inst;
- void *mem_client;
- struct list_head registered_bufs;
-};
-
static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
{
return container_of(filp->private_data,
struct msm_vidc_inst, event_handler);
}
-static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
- void *fh)
-{
- struct msm_vidc_inst *vidc_inst;
- vidc_inst = container_of(filp->private_data,
- struct msm_vidc_inst, event_handler);
- return (struct msm_v4l2_vid_inst *)vidc_inst->priv;
-}
-
-struct buffer_info *get_registered_buf(struct list_head *list,
- int fd, u32 buff_off, u32 size, int *plane)
-{
- struct buffer_info *temp;
- struct buffer_info *ret = NULL;
- int i;
- if (!list || fd < 0 || !plane) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- *plane = 0;
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->fd[i] == fd &&
- (CONTAINS(temp->buff_off[i],
- temp->size[i], buff_off)
- || CONTAINS(buff_off,
- size, temp->buff_off[i])
- || OVERLAPS(buff_off, size,
- temp->buff_off[i],
- temp->size[i]))) {
- dprintk(VIDC_DBG,
- "This memory region is already mapped\n");
- ret = temp;
- *plane = i;
- break;
- }
- }
- if (ret)
- break;
- }
- }
-err_invalid_input:
- return ret;
-}
-
-struct buffer_info *get_same_fd_buffer(struct list_head *list,
- int fd, int *plane)
-{
- struct buffer_info *temp;
- struct buffer_info *ret = NULL;
- int i;
- if (!list || fd < 0 || !plane) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- *plane = 0;
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->fd[i] == fd) {
- dprintk(VIDC_INFO,
- "Found same fd buffer\n");
- ret = temp;
- *plane = i;
- break;
- }
- }
- if (ret)
- break;
- }
- }
-err_invalid_input:
- return ret;
-}
-
-static struct buffer_info *device_to_uvaddr(
- struct list_head *list, u32 device_addr)
-{
- struct buffer_info *temp = NULL;
- int found = 0;
- int i;
- if (!list || !device_addr) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->device_addr[i]
- == device_addr) {
- dprintk(VIDC_INFO,
- "Found same fd buffer\n");
- found = 1;
- break;
- }
- }
- if (found)
- break;
- }
- }
-err_invalid_input:
- return temp;
-}
-
static int msm_v4l2_open(struct file *filp)
{
- int rc = 0;
struct video_device *vdev = video_devdata(filp);
struct msm_video_device *vid_dev =
container_of(vdev, struct msm_video_device, vdev);
struct msm_vidc_core *core = video_drvdata(filp);
- struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
- GFP_KERNEL);
- if (!v4l2_inst) {
- dprintk(VIDC_ERR,
- "Failed to allocate memory for this instance\n");
- rc = -ENOMEM;
- goto fail_nomem;
- }
- v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION, &core->resources);
- if (!v4l2_inst->mem_client) {
- dprintk(VIDC_ERR, "Failed to create memory client\n");
- rc = -ENOMEM;
- goto fail_mem_client;
- }
+ struct msm_vidc_inst *vidc_inst;
- v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
- if (!v4l2_inst->vidc_inst) {
+ vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+ if (!vidc_inst) {
dprintk(VIDC_ERR,
"Failed to create video instance, core: %d, type = %d\n",
core->id, vid_dev->type);
- rc = -ENOMEM;
- goto fail_open;
+ return -ENOMEM;
}
- INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
- v4l2_inst->vidc_inst->priv = v4l2_inst;
clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
- filp->private_data = &(v4l2_inst->vidc_inst->event_handler);
- return rc;
-fail_open:
- msm_smem_delete_client(v4l2_inst->mem_client);
-fail_mem_client:
- kfree(v4l2_inst);
-fail_nomem:
- return rc;
-}
-static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
- int buffer_type)
-{
- struct list_head *ptr, *next;
- struct buffer_info *bi;
- struct v4l2_buffer buffer_info;
- struct v4l2_plane plane[VIDEO_MAX_PLANES];
- int rc = 0;
- int i;
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == buffer_type) {
- buffer_info.type = bi->type;
- for (i = 0; (i < bi->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- plane[i].reserved[0] = bi->fd[i];
- plane[i].reserved[1] = bi->buff_off[i];
- plane[i].length = bi->size[i];
- plane[i].m.userptr = bi->device_addr[i];
- buffer_info.m.planes = plane;
- dprintk(VIDC_DBG,
- "Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[i].reserved[0],
- buffer_info.m.planes[i].reserved[1],
- buffer_info.m.planes[i].length);
- }
- buffer_info.length = bi->num_planes;
- rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
- &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "Failed Release buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
- list_del(&bi->list);
- for (i = 0; i < bi->num_planes; i++) {
- if (bi->handle[i])
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle[i]);
- }
- kfree(bi);
- }
- }
- return rc;
+ filp->private_data = &(vidc_inst->event_handler);
+ return 0;
}
static int msm_v4l2_close(struct file *filp)
{
int rc = 0;
- struct list_head *ptr, *next;
- struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- int i;
vidc_inst = get_vidc_inst(filp, NULL);
- v4l2_inst = get_v4l2_inst(filp, NULL);
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- list_del(&bi->list);
- for (i = 0; (i < bi->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (bi->handle[i])
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle[i]);
- }
- kfree(bi);
- }
- }
- msm_smem_delete_client(v4l2_inst->mem_client);
+
rc = msm_vidc_close(vidc_inst);
- kfree(v4l2_inst);
return rc;
}
@@ -339,11 +124,9 @@
struct v4l2_requestbuffers *b)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- struct msm_v4l2_vid_inst *v4l2_inst;
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (b->count == 0)
- rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
+ rc = msm_vidc_release_buffers(vidc_inst, b->type);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
@@ -353,247 +136,19 @@
int msm_v4l2_prepare_buf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_smem *handle = NULL;
- struct buffer_info *binfo;
- struct buffer_info *temp;
- struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- int plane = 0;
- int i, rc = 0;
- struct hfi_device *hdev;
- enum hal_buffer buffer_type;
-
- vidc_inst = get_vidc_inst(file, fh);
- v4l2_inst = get_v4l2_inst(file, fh);
- if (!v4l2_inst || !vidc_inst || !vidc_inst->core
- || !vidc_inst->core->device) {
- rc = -EINVAL;
- goto exit;
- }
-
- hdev = vidc_inst->core->device;
-
- if (!v4l2_inst->mem_client) {
- dprintk(VIDC_ERR, "Failed to get memory client\n");
- rc = -ENOMEM;
- goto exit;
- }
- binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
- if (!binfo) {
- dprintk(VIDC_ERR, "Out of memory\n");
- rc = -ENOMEM;
- goto exit;
- }
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
- b->length, VIDEO_MAX_PLANES);
- rc = -EINVAL;
- goto exit;
- }
- for (i = 0; i < b->length; ++i) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].length) {
- continue;
- }
- temp = get_registered_buf(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length, &plane);
- if (temp) {
- dprintk(VIDC_DBG,
- "This memory region has already been prepared\n");
- rc = -EINVAL;
- kfree(binfo);
- goto exit;
- }
-
- if (vidc_inst->session_type == MSM_VIDC_DECODER) {
- if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- buffer_type = HAL_BUFFER_INPUT;
- else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
- buffer_type = HAL_BUFFER_OUTPUT;
- } else {
- /* FIXME in the future. See comment in msm_comm_get_\
- * domain_partition. Same problem here. */
- if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- buffer_type = HAL_BUFFER_OUTPUT;
- else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
- buffer_type = HAL_BUFFER_INPUT;
- }
-
- temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0], &plane);
-
- if (temp) {
- binfo->type = b->type;
- binfo->fd[i] = b->m.planes[i].reserved[0];
- binfo->buff_off[i] = b->m.planes[i].reserved[1];
- binfo->size[i] = b->m.planes[i].length;
- binfo->uvaddr[i] = b->m.planes[i].m.userptr;
- binfo->device_addr[i] =
- temp->handle[plane]->device_addr + binfo->buff_off[i];
- binfo->handle[i] = NULL;
- } else {
- handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- buffer_type);
- if (!handle) {
- dprintk(VIDC_ERR,
- "Failed to get device buffer address\n");
- kfree(binfo);
- goto exit;
- }
- binfo->type = b->type;
- binfo->fd[i] = b->m.planes[i].reserved[0];
- binfo->buff_off[i] = b->m.planes[i].reserved[1];
- binfo->size[i] = b->m.planes[i].length;
- binfo->uvaddr[i] = b->m.planes[i].m.userptr;
- binfo->device_addr[i] =
- handle->device_addr + binfo->buff_off[i];
- binfo->handle[i] = handle;
- dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_CLEAN);
- if (rc)
- dprintk(VIDC_WARN,
- "CACHE Clean failed: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- }
- b->m.planes[i].m.userptr = binfo->device_addr[i];
- }
- binfo->num_planes = b->length;
- list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
- rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
-exit:
- return rc;
+ return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_qbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- struct buffer_info *binfo;
- int plane = 0;
- int rc = 0;
- int i;
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
- b->length);
- return -EINVAL;
- }
- vidc_inst = get_vidc_inst(file, fh);
- v4l2_inst = get_v4l2_inst(file, fh);
- for (i = 0; i < b->length; ++i) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].length) {
- b->m.planes[i].m.userptr = 0;
- continue;
- }
- binfo = get_registered_buf(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length, &plane);
- if (!binfo) {
- dprintk(VIDC_ERR,
- "This buffer is not registered: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- rc = -EINVAL;
- goto err_invalid_buff;
- }
- b->m.planes[i].m.userptr = binfo->device_addr[i];
- dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
- binfo->device_addr[i]);
-
- if ((vidc_inst->fmts[OUTPUT_PORT]->fourcc ==
- V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_INVALIDATE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to INV caches: %d\n", rc);
- goto err_invalid_buff;
- }
- }
-
- if (binfo->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_CLEAN);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to clean caches: %d\n", rc);
- goto err_invalid_buff;
- }
- }
- }
- rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
-err_invalid_buff:
- return rc;
+ return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- int rc = 0;
- int i;
- struct msm_v4l2_vid_inst *v4l2_inst;
- struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- struct buffer_info *buffer_info;
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
- b->length);
- return -EINVAL;
- }
- v4l2_inst = get_v4l2_inst(file, fh);
- rc = msm_vidc_dqbuf((void *)vidc_inst, b);
- if (rc) {
- dprintk(VIDC_DBG,
- "Failed to dqbuf, capability: %d, rc: %d\n",
- b->type, rc);
- goto fail_dq_buf;
- }
- for (i = 0; i < b->length; i++) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].m.userptr) {
- continue;
- }
- buffer_info = device_to_uvaddr(
- &v4l2_inst->registered_bufs,
- b->m.planes[i].m.userptr);
- b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
- if (!b->m.planes[i].m.userptr) {
- dprintk(VIDC_ERR,
- "Failed to find user virtual address, 0x%lx, %d, %d\n",
- b->m.planes[i].m.userptr, b->type, i);
- rc = -EINVAL;
- goto fail_dq_buf;
- }
- if (buffer_info->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to clean caches: %d\n", rc);
- goto fail_dq_buf;
- }
- }
- }
-fail_dq_buf:
- return rc;
+ return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_streamon(struct file *file, void *fh,
@@ -629,12 +184,10 @@
static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
- struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (dec->cmd == V4L2_DEC_CMD_STOP)
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
@@ -645,12 +198,10 @@
static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
- struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (enc->cmd == V4L2_ENC_CMD_STOP)
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 4ca66db..ea91849 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -12,7 +12,7 @@
*/
#include <linux/slab.h>
-
+#include <mach/scm.h>
#include "msm_vidc_internal.h"
#include "msm_vidc_common.h"
#include "vidc_hfi_api.h"
@@ -24,6 +24,14 @@
#define MAX_NUM_OUTPUT_BUFFERS 6
#define DEFAULT_CONCEAL_COLOR 0x0
+#define TZ_INFO_GET_FEATURE_VERSION_ID 0x3
+#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
+#define TZ_FEATURE_VERSION(major, minor, patch) \
+ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+struct tz_get_feature_version {
+ u32 feature_id;
+};
+
enum msm_vdec_ctrl_cluster {
MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
};
@@ -72,6 +80,7 @@
static const char *const mpeg_vidc_video_alloc_mode_type[] = {
"Buffer Allocation Static",
"Buffer Allocation Ring Buffer",
+ "Buffer Allocation Dynamic Buffer"
};
static const char *const perf_level[] = {
@@ -255,15 +264,32 @@
.step = 0,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE,
- .name = "Buffer allocation mode",
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+ .name = "Buffer allocation mode for input",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
- .maximum = V4L2_MPEG_VIDC_VIDEO_RING,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
- (1 << V4L2_MPEG_VIDC_VIDEO_RING)
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+ ),
+ .qmenu = mpeg_vidc_video_alloc_mode_type,
+ .step = 0,
+ .cluster = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+ .name = "Buffer allocation mode for output",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
),
.qmenu = mpeg_vidc_video_alloc_mode_type,
.step = 0,
@@ -1293,21 +1319,58 @@
inst->capability.width.max = DEFAULT_WIDTH;
inst->capability.buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->capability.buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = 30;
return rc;
}
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+ switch (val) {
+ case V4L2_MPEG_VIDC_VIDEO_STATIC:
+ return HAL_BUFFER_MODE_STATIC;
+ case V4L2_MPEG_VIDC_VIDEO_RING:
+ return HAL_BUFFER_MODE_RING;
+ case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+ return HAL_BUFFER_MODE_DYNAMIC;
+ default:
+ dprintk(VIDC_ERR, "%s: invalid buf type: %d", __func__, val);
+ }
+ return 0;
+}
+
+static int check_tz_dynamic_buffer_support(void)
+{
+ int rc = 0;
+ struct tz_get_feature_version tz_feature_id;
+ unsigned int resp = 0;
+
+ tz_feature_id.feature_id = TZ_DYNAMIC_BUFFER_FEATURE_ID;
+ rc = scm_call(SCM_SVC_INFO,
+ TZ_INFO_GET_FEATURE_VERSION_ID, &tz_feature_id,
+ sizeof(tz_feature_id), &resp, sizeof(resp));
+ if ((rc) || (resp != TZ_FEATURE_VERSION(1, 1, 0))) {
+ dprintk(VIDC_DBG,
+ "Dyamic buffer mode not supported, failed to get tz feature version id : %u, rc : %d, response : %u\n",
+ tz_feature_id.feature_id, rc, resp);
+ rc = -ENOTSUPP;
+ }
+ return rc;
+}
+
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
- struct hal_enable hal_property;/*, prop;*/
+ struct hal_enable hal_property;
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata = NULL;
struct hfi_device *hdev;
struct hal_extradata_enable extra;
+ struct hal_buffer_alloc_mode alloc_mode;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1396,15 +1459,17 @@
}
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE:
- {
- struct hal_buffer_alloc_mode mode;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+ if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+ rc = -ENOTSUPP;
+ break;
+ }
property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
- mode.buffer_mode = ctrl->val;
- mode.buffer_type = HAL_BUFFER_INPUT;
- pdata = &mode;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+ alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+ inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+ pdata = &alloc_mode;
break;
- }
case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
{
property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
@@ -1412,6 +1477,28 @@
pdata = &hal_property;
break;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+ property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+ if (!(alloc_mode.buffer_mode &
+ inst->capability.buffer_mode[CAPTURE_PORT])) {
+ dprintk(VIDC_DBG,
+ "buffer mode[%d] not supported for Capture Port\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+ if ((alloc_mode.buffer_mode == HAL_BUFFER_MODE_DYNAMIC) &&
+ (inst->flags & VIDC_SECURE) &&
+ check_tz_dynamic_buffer_support()) {
+ rc = -ENOTSUPP;
+ break;
+ }
+ alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &alloc_mode;
+ inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+ break;
+
default:
break;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c1a9ad0..9e8a639 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1953,6 +1953,8 @@
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
inst->prop.fps = 15;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 4258a10..89fbc2a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -199,6 +199,478 @@
return -EINVAL;
}
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b, int idx, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ int i;
+ struct list_head *list = &inst->registered_bufs;
+ int fd = b->m.planes[idx].reserved[0];
+ u32 buff_off = b->m.planes[idx].reserved[1];
+ u32 size = b->m.planes[idx].length;
+ u32 device_addr = b->m.planes[idx].m.userptr;
+
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+
+ *plane = 0;
+ mutex_lock(&inst->lock);
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp &&
+ ((fd == temp->fd[i]) ||
+ (device_addr == temp->device_addr[i])) &&
+ (CONTAINS(temp->buff_off[i],
+ temp->size[i], buff_off)
+ || CONTAINS(buff_off,
+ size, temp->buff_off[i])
+ || OVERLAPS(buff_off, size,
+ temp->buff_off[i],
+ temp->size[i]))) {
+ dprintk(VIDC_DBG,
+ "This memory region is already mapped\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return ret;
+}
+
+struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
+ struct list_head *list, int fd, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ int i;
+ if (fd == 0)
+ return NULL;
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+ *plane = 0;
+ mutex_lock(&inst->lock);
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd) {
+ temp->same_fd_ref[i]++;
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return ret;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+ struct list_head *list, u32 device_addr)
+{
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ int found = 0;
+ int i;
+ if (!list || !device_addr || !inst) {
+ dprintk(VIDC_ERR,
+ "Invalid input- list: %p device_addr: %u inst: %p\n",
+ list, device_addr, inst);
+ goto err_invalid_input;
+ }
+ mutex_lock(&inst->lock);
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && !temp->inactive &&
+ temp->device_addr[i] == device_addr) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+ struct v4l2_buffer *b, u32 i)
+{
+ binfo->type = b->type;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->num_planes = b->length;
+ binfo->memory = b->memory;
+ binfo->v4l2_index = b->index;
+ binfo->dequeued = false;
+ binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+ binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+ dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+ __func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ b->type = binfo->type;
+ b->length = binfo->num_planes;
+ b->memory = binfo->memory;
+ b->index = binfo->v4l2_index;
+ b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+ b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+ for (i = 0; i < binfo->num_planes; ++i) {
+ b->m.planes[i].reserved[0] = binfo->fd[i];
+ b->m.planes[i].reserved[1] = binfo->buff_off[i];
+ b->m.planes[i].length = binfo->size[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "%s %d %d %d %u\n", __func__, binfo->fd[i],
+ binfo->buff_off[i], binfo->size[i],
+ binfo->device_addr[i]);
+ }
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+ struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+ struct msm_smem *handle = NULL;
+ handle = msm_smem_user_to_kernel(inst->mem_client,
+ p->reserved[0],
+ p->reserved[1],
+ buffer_type);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get device buffer address\n", __func__);
+ return NULL;
+ }
+ if (msm_smem_cache_operations(inst->mem_client, handle,
+ SMEM_CACHE_CLEAN))
+ dprintk(VIDC_WARN,
+ "CACHE Clean failed: %d, %d, %d\n",
+ p->reserved[0],
+ p->reserved[1],
+ p->length);
+ return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+ struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_INPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_OUTPUT;
+ } else {
+ /* FIXME in the future. See comment in msm_comm_get_\
+ * domain_partition. Same problem here. */
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_OUTPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_INPUT;
+ }
+ return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+ struct msm_vidc_inst *inst)
+{
+ return ((b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+ (inst->buffer_mode_set[CAPTURE_PORT] ==
+ HAL_BUFFER_MODE_DYNAMIC));
+}
+
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ populate_buf_info(binfo, b, i);
+ }
+}
+
+int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buffer_info *binfo = NULL;
+ struct buffer_info *temp = NULL;
+ int plane = 0;
+ int i = 0, rc = 0;
+
+ if (!b || !inst) {
+ dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+ b->length, VIDEO_MAX_PLANES);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d\n",
+ binfo, b->m.planes[0].reserved[0], b->type);
+
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ temp = get_registered_buf(inst, b, i, &plane);
+ if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
+ dprintk(VIDC_DBG,
+ "This memory region has already been prepared\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (temp && is_dynamic_output_buffer_mode(b, inst) &&
+ (i == 0)) {
+ /*
+ * Buffer is already present in registered list
+ * increment ref_count, populate new values of v4l2
+ * buffer in existing buffer_info struct.
+ *
+ * We will use the saved buffer info and queue it when
+ * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+ */
+ dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+ rc = buf_ref_get(inst, temp);
+ if (rc < 0)
+ return rc;
+ save_v4l2_buffer(b, temp);
+ rc = -EEXIST;
+ goto exit;
+ }
+
+ temp = get_same_fd_buffer(inst, &inst->registered_bufs,
+ b->m.planes[i].reserved[0], &plane);
+
+ populate_buf_info(binfo, b, i);
+ if (temp) {
+ binfo->device_addr[i] =
+ temp->handle[plane]->device_addr + binfo->buff_off[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ binfo->mapped[i] = false;
+ } else {
+ if (inst->map_output_buffer) {
+ binfo->handle[i] =
+ map_buffer(inst, &b->m.planes[i],
+ get_hal_buffer_type(inst, b));
+ if (!binfo->handle[i]) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ dprintk(VIDC_DBG,
+ "[MAP] - mapped handle[%d] = %p fd[%d] = %d",
+ i, binfo->handle[i], i, binfo->fd[i]);
+ binfo->mapped[i] = true;
+ binfo->device_addr[i] =
+ binfo->handle[i]->device_addr +
+ binfo->buff_off[i];
+ b->m.planes[i].m.userptr =
+ binfo->device_addr[i];
+ } else {
+ binfo->device_addr[i] =
+ b->m.planes[i].m.userptr;
+ }
+ dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ }
+ /* We maintain one ref count for all planes*/
+ if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
+ rc = buf_ref_get(inst, binfo);
+ if (rc < 0)
+ return rc;
+ }
+ }
+ dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo);
+ mutex_lock(&inst->lock);
+ list_add_tail(&binfo->list, &inst->registered_bufs);
+ mutex_unlock(&inst->lock);
+ return 0;
+exit:
+ kfree(binfo);
+ return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ struct list_head *list;
+ bool found = false, keep_node = false;
+
+ if (!inst || !binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p %p\n",
+ __func__, inst, binfo);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst->lock);
+ list = &inst->registered_bufs;
+ /*
+ * Make sure the buffer to be unmapped and deleted
+ * from the registered list is present in the list.
+ */
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ if (temp == binfo) {
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * Free the buffer info only if
+ * - buffer info has not been deleted from registered list
+ * - vidc client has called dqbuf on the buffer
+ * - no references are held on the buffer
+ */
+ if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+ goto exit;
+
+ for (i = 0; i < temp->num_planes; i++) {
+ /*
+ * Unmap the handle only if the buffer has been mapped and no
+ * other buffer has a reference to this buffer.
+ * In case of buffers with same fd, we will map the buffer only
+ * once and subsequent buffers will refer to the mapped buffer's
+ * device address.
+ * For buffers which share the same fd, do not unmap and keep
+ * the buffer info in registered list.
+ */
+ if (temp->handle[i] && temp->mapped[i] &&
+ !temp->same_fd_ref[i]) {
+ dprintk(VIDC_DBG,
+ "[UNMAP] - handle[%d] = %p fd[%d] = %d",
+ i, temp->handle[i], i, temp->fd[i]);
+ msm_smem_free(inst->mem_client,
+ temp->handle[i]);
+ }
+
+ if (temp->same_fd_ref[i])
+ keep_node = true;
+ else {
+ temp->fd[i] = 0;
+ temp->handle[i] = 0;
+ temp->device_addr[i] = 0;
+ temp->uvaddr[i] = 0;
+ }
+ }
+ if (!keep_node) {
+ dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp);
+ list_del(&temp->list);
+ kfree(temp);
+ } else {
+ temp->inactive = true;
+ dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp);
+ }
+exit:
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ struct v4l2_buffer b = {0};
+ struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+ b.m.planes = plane;
+ repopulate_v4l2_buffer(&b, binfo);
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(inst, &b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(inst, &b);
+
+ return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ int rc = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return -EINVAL;
+ }
+
+ if (!inst->map_output_buffer)
+ return 0;
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n",
+ __func__, inst);
+ return -EINVAL;
+ }
+
+ if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return 0;
+
+
+ for (i = 0; i < binfo->num_planes; i++) {
+ if (binfo->handle[i]) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to clean caches: %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
@@ -206,6 +678,19 @@
if (!inst || !b)
return -EINVAL;
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ dprintk(VIDC_ERR, "%s: not supported in dynamic buffer mode\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Map the buffer only for non-kernel clients*/
+ if (b->m.planes[0].reserved[0]) {
+ inst->map_output_buffer = true;
+ if (map_and_register_buf(inst, b))
+ return -EINVAL;
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_prepare_buf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
@@ -213,18 +698,58 @@
return -EINVAL;
}
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+int msm_vidc_release_buffers(void *instance, int buffer_type)
{
+ struct list_head *ptr, *next;
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *bi;
+ struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane[VIDEO_MAX_PLANES];
+ int i, rc = 0;
- if (!inst || !b)
+ if (!inst)
return -EINVAL;
- if (inst->session_type == MSM_VIDC_DECODER)
- return msm_vdec_release_buf(instance, b);
- if (inst->session_type == MSM_VIDC_ENCODER)
- return msm_venc_release_buf(instance, b);
- return -EINVAL;
+ list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == buffer_type) {
+ buffer_info.type = bi->type;
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ plane[i].reserved[0] = bi->fd[i];
+ plane[i].reserved[1] = bi->buff_off[i];
+ plane[i].length = bi->size[i];
+ plane[i].m.userptr = bi->device_addr[i];
+ buffer_info.m.planes = plane;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[i].reserved[0],
+ buffer_info.m.planes[i].reserved[1],
+ buffer_info.m.planes[i].length);
+ }
+ buffer_info.length = bi->num_planes;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ rc = msm_vdec_release_buf(instance,
+ &buffer_info);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ rc = msm_venc_release_buf(instance,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ list_del(&bi->list);
+ for (i = 0; i < bi->num_planes; i++) {
+ if (bi->handle[i])
+ msm_smem_free(inst->mem_client,
+ bi->handle[i]);
+ }
+ kfree(bi);
+ }
+ }
+ return rc;
}
int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
@@ -246,29 +771,149 @@
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *binfo;
+ int plane = 0;
+ int rc = 0;
+ int i;
if (!inst || !b)
return -EINVAL;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ if (b->m.planes[0].reserved[0])
+ inst->map_output_buffer = true;
+
+ rc = map_and_register_buf(inst, b);
+ if (rc == -EEXIST)
+ return 0;
+ if (rc)
+ return rc;
+ }
+
+ for (i = 0; i < b->length; ++i) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ b->m.planes[i].m.userptr = 0;
+ continue;
+ }
+
+ binfo = get_registered_buf(inst, b, i, &plane);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ goto err_invalid_buff;
+ }
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
+ binfo->device_addr[i]);
+
+ if ((inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to inv caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_qbuf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
return -EINVAL;
}
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *buffer_info = NULL;
+ int i = 0, rc = 0;
if (!inst || !b)
return -EINVAL;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
- return msm_vdec_dqbuf(instance, b);
+ rc = msm_vdec_dqbuf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
- return msm_venc_dqbuf(instance, b);
- return -EINVAL;
+ rc = msm_venc_dqbuf(instance, b);
+
+ if (rc)
+ return rc;
+
+ for (i = 0; i < b->length; i++) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].m.userptr) {
+ continue;
+ }
+ buffer_info = device_to_uvaddr(inst,
+ &inst->registered_bufs,
+ b->m.planes[i].m.userptr);
+
+ if (!buffer_info) {
+ dprintk(VIDC_ERR,
+ "%s no buffer info registered for buffer addr: 0x%lx\n",
+ __func__, b->m.planes[i].m.userptr);
+ return -EINVAL;
+ }
+
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+ if (!b->m.planes[i].m.userptr) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to find user virtual address, 0x%lx, %d, %d\n",
+ __func__, b->m.planes[i].m.userptr, b->type, i);
+ return -EINVAL;
+ }
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ mutex_lock(&inst->lock);
+ buffer_info->dequeued = true;
+ mutex_unlock(&inst->lock);
+ dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+ buffer_info->fd[0]);
+ rc = unmap_and_deregister_buf(inst, buffer_info);
+ } else
+ rc = output_buffer_cache_invalidate(inst, buffer_info);
+
+ return rc;
}
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
@@ -450,9 +1095,11 @@
INIT_LIST_HEAD(&inst->internalbufs);
INIT_LIST_HEAD(&inst->persistbufs);
INIT_LIST_HEAD(&inst->ctrl_clusters);
+ INIT_LIST_HEAD(&inst->registered_bufs);
init_waitqueue_head(&inst->kernel_event_queue);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
+ inst->map_output_buffer = false;
for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
@@ -572,12 +1219,27 @@
struct msm_vidc_inst *temp;
struct msm_vidc_core *core;
struct list_head *ptr, *next;
+ struct buffer_info *bi;
int rc = 0;
int i;
if (!inst)
return -EINVAL;
+ list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ list_del(&bi->list);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (bi->handle[i])
+ msm_smem_free(inst->mem_client,
+ bi->handle[i]);
+ }
+ kfree(bi);
+ }
+ }
+
core = inst->core;
mutex_lock(&core->sync_lock);
list_for_each_safe(ptr, next, &core->instances) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 0e0328a..780f2c4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -31,6 +31,8 @@
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+ V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
#define NUM_MBS_PER_SEC(__height, __width, __fps) ({\
(__height >> 4) * (__width >> 4) * __fps; \
@@ -471,14 +473,72 @@
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
break;
+ case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+ {
+ struct v4l2_event buf_event = {0};
+ struct buffer_info *binfo = NULL;
+ u32 *ptr = NULL;
+
+ dprintk(VIDC_DBG,
+ "%s - inst: %p buffer: %p extra: %p\n",
+ __func__, inst,
+ event_notify->packet_buffer,
+ event_notify->exra_data_buffer);
+
+ /*
+ * Get the buffer_info entry for the
+ * device address.
+ */
+ binfo = device_to_uvaddr(inst,
+ &inst->registered_bufs,
+ (u32)event_notify->packet_buffer);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+
+ /* Fill event data to be sent to client*/
+ buf_event.type =
+ V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+
+ dprintk(VIDC_DBG,
+ "RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
+ ptr[0], ptr[1]);
+
+ /* Decrement buffer reference count*/
+ buf_ref_put(inst, binfo);
+
+ /*
+ * Release buffer and remove from list
+ * if reference goes to zero.
+ */
+ if (unmap_and_deregister_buf(inst, binfo))
+ dprintk(VIDC_ERR,
+ "%s: buffer unmap failed\n", __func__);
+
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler,
+ &buf_event);
+ wake_up(&inst->kernel_event_queue);
+ return;
+ }
default:
break;
}
if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
} else {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
inst->prop.height = event_notify->height;
inst->prop.width = event_notify->width;
}
@@ -807,6 +867,107 @@
}
}
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int cnt = 0;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ mutex_lock(&inst->lock);
+ atomic_inc(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ if (cnt > 2) {
+ dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+ dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+ mutex_unlock(&inst->lock);
+ return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int rc = 0;
+ int cnt;
+ bool release_buf = false;
+ bool qbuf_again = false;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ mutex_lock(&inst->lock);
+ atomic_dec(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+ if (cnt == 0)
+ release_buf = true;
+ else if (cnt == 1)
+ qbuf_again = true;
+ else {
+ dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+ mutex_unlock(&inst->lock);
+
+ if (cnt < 0)
+ return cnt;
+
+ rc = output_buffer_cache_invalidate(inst, binfo);
+ if (rc)
+ return rc;
+
+ if (release_buf) {
+ /*
+ * We can not delete binfo here as we need to set the user
+ * virtual address saved in binfo->uvaddr to the dequeued v4l2
+ * buffer.
+ *
+ * We will set the pending_deletion flag to true here and delete
+ * binfo from registered list in dqbuf after setting the uvaddr.
+ */
+ dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+ binfo->fd[0]);
+ binfo->pending_deletion = true;
+ } else if (qbuf_again) {
+ rc = qbuf_dynamic_buf(inst, binfo);
+ if (!rc)
+ return rc;
+ }
+ return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+ u32 device_addr, u32 flags)
+{
+ struct buffer_info *binfo = NULL;
+
+ /*
+ * Update reference count and release OR queue back the buffer,
+ * only when firmware is not holding a reference.
+ */
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ binfo = device_to_uvaddr(inst, &inst->registered_bufs,
+ device_addr);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+ if (flags & HAL_BUFFERFLAG_READONLY) {
+ dprintk(VIDC_DBG,
+ "_F_B_D_ fd[0] = %d -> Reference with f/w",
+ binfo->fd[0]);
+ } else {
+ dprintk(VIDC_DBG,
+ "_F_B_D_ fd[0] = %d -> FBD_ref_released\n",
+ binfo->fd[0]);
+ buf_ref_put(inst, binfo);
+ }
+ }
+}
+
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -850,6 +1011,10 @@
}
vb->v4l2_buf.flags = 0;
+ handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1,
+ fill_buf_done->flags1);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
@@ -2400,6 +2565,67 @@
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
return;
}
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *binfo = NULL, *dummy = NULL;
+ struct list_head *list = NULL;
+
+ if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+ return;
+
+ /*
+ * dynamic buffer mode:- if flush is called during seek
+ * driver should not queue any new buffer it has been holding.
+ *
+ * Each dynamic o/p buffer can have one of following ref_count:
+ * ref_count : 0 - f/w has released reference and sent fbd back.
+ * The buffer has been returned back to client.
+ *
+ * ref_count : 1 - f/w is holding reference. f/w may have released
+ * fbd as read_only OR fbd is pending. f/w will
+ * release reference before sending flush_done.
+ *
+ * ref_count : 2 - f/w is holding reference, f/w has released fbd as
+ * read_only, which client has queued back to driver.
+ * driver holds this buffer and will queue back
+ * only when f/w releases the reference. During
+ * flush_done, f/w will release the reference but driver
+ * should not queue back the buffer to f/w.
+ * Flush all buffers with ref_count 2.
+ */
+ mutex_lock(&inst->lock);
+ if (!list_empty(&inst->registered_bufs)) {
+ struct v4l2_event buf_event = {0};
+ u32 *ptr = NULL;
+ list = &inst->registered_bufs;
+ list_for_each_entry_safe(binfo, dummy, list, list) {
+ if (binfo &&
+ (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+ (atomic_read(&binfo->ref_count) == 2)) {
+ atomic_dec(&binfo->ref_count);
+ buf_event.type =
+ V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+ ptr[2] = binfo->uvaddr[0];
+ ptr[3] = (u32) binfo->timestamp.tv_sec;
+ ptr[4] = (u32) binfo->timestamp.tv_usec;
+ ptr[5] = binfo->v4l2_index;
+ dprintk(VIDC_DBG,
+ "released buffer held in driver before issuing flush: 0x%x fd[0]: %d\n",
+ binfo->device_addr[0], binfo->fd[0]);
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler,
+ &buf_event);
+ wake_up(&inst->kernel_event_queue);
+ }
+ }
+ }
+ mutex_unlock(&inst->lock);
+}
+
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
{
int rc = 0;
@@ -2475,6 +2701,9 @@
kfree(temp);
}
}
+
+ msm_comm_flush_dynamic_buffers(inst);
+
/*Do not send flush in case of session_error */
if (!(inst->state == MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID))
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 03136ae..25651c9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -36,6 +36,10 @@
__buf.filled_size = 0; \
})
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+ atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
static int core_info_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -193,6 +197,37 @@
return 0;
}
+static int publish_unreleased_reference(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ struct list_head *list = NULL;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ list = &inst->registered_bufs;
+ mutex_lock(&inst->lock);
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ if (temp && temp->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ !temp->inactive && atomic_read(&temp->ref_count)) {
+ write_str(&dbg_buf,
+ "\tpending buffer: 0x%x fd[0] = %d ref_count = %d held by: %s\n",
+ temp->device_addr[0],
+ temp->fd[0],
+ atomic_read(&temp->ref_count),
+ DYNAMIC_BUF_OWNER(temp));
+ }
+ }
+ }
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
static ssize_t inst_info_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -221,6 +256,19 @@
write_str(
&dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
"Output" : "Capture");
+ switch (inst->buffer_mode_set[i]) {
+ case HAL_BUFFER_MODE_STATIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "static");
+ break;
+ case HAL_BUFFER_MODE_RING:
+ write_str(&dbg_buf, "buffer mode : %s\n", "ring");
+ break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "dynamic");
+ break;
+ default:
+ write_str(&dbg_buf, "buffer mode : unsupported\n");
+ }
for (j = 0; j < inst->fmts[i]->num_planes; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
inst->bufq[i].vb2_bufq.plane_sizes[j]);
@@ -235,6 +283,8 @@
write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
+ publish_unreleased_reference(inst);
+
return simple_read_from_buffer(buf, count, ppos,
dbg_buf.ptr, dbg_buf.filled_size);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 0a078bd..b17cb5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -14,7 +14,9 @@
#ifndef _MSM_VIDC_INTERNAL_H_
#define _MSM_VIDC_INTERNAL_H_
+#include <linux/atomic.h>
#include <linux/list.h>
+#include <linux/time.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/wait.h>
@@ -228,6 +230,9 @@
struct buf_count count;
enum msm_vidc_modes flags;
struct msm_vidc_core_capability capability;
+ enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+ struct list_head registered_bufs;
+ bool map_output_buffer;
};
extern struct msm_vidc_drv *vidc_driver;
@@ -257,4 +262,35 @@
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int num_planes;
+ int fd[VIDEO_MAX_PLANES];
+ int buff_off[VIDEO_MAX_PLANES];
+ int size[VIDEO_MAX_PLANES];
+ u32 uvaddr[VIDEO_MAX_PLANES];
+ u32 device_addr[VIDEO_MAX_PLANES];
+ struct msm_smem *handle[VIDEO_MAX_PLANES];
+ enum v4l2_memory memory;
+ u32 v4l2_index;
+ bool pending_deletion;
+ atomic_t ref_count;
+ bool dequeued;
+ bool inactive;
+ bool mapped[VIDEO_MAX_PLANES];
+ int same_fd_ref[VIDEO_MAX_PLANES];
+ struct timeval timestamp;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+ struct list_head *list, u32 device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index af58e22..70b93ff0 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -19,6 +19,7 @@
#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
(HFI_OX_BASE + 0x1)
@@ -138,8 +139,10 @@
(HFI_PROPERTY_PARAM_OX_START + 0x008)
#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x009)
-#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00B)
#define HFI_PROPERTY_CONFIG_OX_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index e5d6040..1c9b71d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -864,6 +864,7 @@
enum hal_event_type {
HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+ HAL_EVENT_RELEASE_BUFFER_REFERENCE,
HAL_UNUSED_SEQCHG = 0x10000000,
};
@@ -932,6 +933,8 @@
u32 height;
u32 width;
u32 hal_event_type;
+ u8 *packet_buffer;
+ u8 *exra_data_buffer;
};
/* Data callback structure */
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 050a98d..6589a7cf 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -849,6 +849,12 @@
u32 rg_ext_event_data[1];
};
+struct hfi_msg_release_buffer_ref_event_packet {
+ u8 *packet_buffer;
+ u8 *exra_data_buffer;
+ u32 output_tag;
+};
+
struct hfi_msg_sys_init_done_packet {
u32 size;
u32 packet_type;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index e1c096b..af206c7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -707,6 +707,7 @@
#define V4L2_QCOM_BUF_DROP_FRAME 0x100000
#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
#define V4L2_QCOM_BUF_FLAG_EOS 0x2000
+#define V4L2_QCOM_BUF_FLAG_READONLY 0x400000
/*
* O V E R L A Y P R E V I E W
@@ -1863,22 +1864,25 @@
V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
};
-#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE \
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
(V4L2_CID_MPEG_MSM_VIDC_BASE+30)
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
enum v4l2_mpeg_vidc_video_alloc_mode_type {
V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
V4L2_MPEG_VIDC_VIDEO_RING = 1,
+ V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
};
#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+32)
enum v4l2_mpeg_vidc_video_assembly {
V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
};
#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+33)
enum v4l2_mpeg_vidc_video_vp8_profile_level {
V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
@@ -2448,7 +2452,10 @@
(V4L2_EVENT_MSM_VIDC_START + 3)
#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4)
#define V4L2_EVENT_MSM_VIDC_SYS_ERROR (V4L2_EVENT_MSM_VIDC_START + 5)
-
+#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \
+ (V4L2_EVENT_MSM_VIDC_START + 6)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
+ (V4L2_EVENT_MSM_VIDC_START + 7)
/* Payload for V4L2_EVENT_VSYNC */
struct v4l2_event_vsync {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 2164275..868be9f 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);