M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
/* Copyright (c) 2010, 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef VDEC_INTERNAL_H
#define VDEC_INTERNAL_H
#include <linux/msm_vidc_dec.h>
#include <linux/cdev.h>
#include <media/msm/vidc_init.h>
#define NUM_OF_DRIVER_NODES 2
struct vid_dec_msg {
struct list_head list;
struct vdec_msginfo vdec_msg_info;
};
struct vid_dec_dev {
struct cdev cdev[NUM_OF_DRIVER_NODES];
struct device *device[NUM_OF_DRIVER_NODES];
resource_size_t phys_base;
void __iomem *virt_base;
unsigned int irq;
struct clk *hclk;
struct clk *hclk_div2;
struct clk *pclk;
unsigned long hclk_rate;
struct mutex lock;
s32 device_handle;
struct video_client_ctx vdec_clients[VIDC_MAX_NUM_CLIENTS];
u32 num_clients;
void(*timer_handler)(void *);
};
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,170 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef VENC_INTERNAL_H
#define VENC_INTERNAL_H
#include <linux/msm_vidc_enc.h>
#include <linux/cdev.h>
#include <media/msm/vidc_init.h>
#define NUM_OF_DRIVER_NODES 2
#define VID_ENC_MAX_NUM_OF_BUFF 100
enum venc_buffer_dir{
VEN_BUFFER_TYPE_INPUT,
VEN_BUFFER_TYPE_OUTPUT
};
struct vid_enc_msg {
struct list_head list;
struct venc_msg venc_msg_info;
};
struct vid_enc_dev {
struct cdev cdev[NUM_OF_DRIVER_NODES];
struct device *device[NUM_OF_DRIVER_NODES];
resource_size_t phys_base;
void __iomem *virt_base;
unsigned int irq;
struct clk *hclk;
struct clk *hclk_div2;
struct clk *pclk;
unsigned long hclk_rate;
struct mutex lock;
s32 device_handle;
struct video_client_ctx venc_clients[VIDC_MAX_NUM_CLIENTS];
u32 num_clients;
};
u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
struct venc_basecfg *base_config, u32 set_flag);
u32 vid_enc_set_get_inputformat(struct video_client_ctx *client_ctx,
u32 *input_format, u32 set_flag);
u32 vid_enc_set_get_codec(struct video_client_ctx *client_ctx, u32 *codec,
u32 set_flag);
u32 vid_enc_set_get_framesize(struct video_client_ctx *client_ctx,
u32 *height, u32 *width, u32 set_flag);
u32 vid_enc_set_get_bitrate(struct video_client_ctx *client_ctx,
struct venc_targetbitrate *venc_bitrate, u32 set_flag);
u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
struct venc_framerate *frame_rate, u32 set_flag);
u32 vid_enc_set_get_live_mode(struct video_client_ctx *client_ctx,
struct venc_switch *encoder_switch, u32 set_flag);
u32 vid_enc_set_get_extradata(struct video_client_ctx *client_ctx,
u32 *extradata_flag, u32 set_flag);
u32 vid_enc_set_get_short_header(struct video_client_ctx *client_ctx,
struct venc_switch *encoder_switch, u32 set_flag);
u32 vid_enc_set_get_profile(struct video_client_ctx *client_ctx,
struct venc_profile *profile, u32 set_flag);
u32 vid_enc_set_get_profile_level(struct video_client_ctx *client_ctx,
struct ven_profilelevel *profile_level, u32 set_flag);
u32 vid_enc_set_get_session_qp(struct video_client_ctx *client_ctx,
struct venc_sessionqp *session_qp, u32 set_flag);
u32 vid_enc_set_get_intraperiod(struct video_client_ctx *client_ctx,
struct venc_intraperiod *intraperiod, u32 set_flag);
u32 vid_enc_request_iframe(struct video_client_ctx *client_ctx);
u32 vid_enc_get_sequence_header(struct video_client_ctx *client_ctx,
struct venc_seqheader *seq_header);
u32 vid_enc_set_get_entropy_cfg(struct video_client_ctx *client_ctx,
struct venc_entropycfg *entropy_cfg, u32 set_flag);
u32 vid_enc_set_get_dbcfg(struct video_client_ctx *client_ctx,
struct venc_dbcfg *dbcfg, u32 set_flag);
u32 vid_enc_set_get_intrarefresh(struct video_client_ctx *client_ctx,
struct venc_intrarefresh *intrarefresh, u32 set_flag);
u32 vid_enc_set_get_multiclicecfg(struct video_client_ctx *client_ctx,
struct venc_multiclicecfg *multiclicecfg, u32 set_flag);
u32 vid_enc_set_get_ratectrlcfg(struct video_client_ctx *client_ctx,
struct venc_ratectrlcfg *ratectrlcfg, u32 set_flag);
u32 vid_enc_set_get_voptimingcfg(struct video_client_ctx *client_ctx,
struct venc_voptimingcfg *voptimingcfg, u32 set_flag);
u32 vid_enc_set_get_headerextension(struct video_client_ctx *client_ctx,
struct venc_headerextension *headerextension, u32 set_flag);
u32 vid_enc_set_get_qprange(struct video_client_ctx *client_ctx,
struct venc_qprange *qprange, u32 set_flag);
u32 vid_enc_start_stop(struct video_client_ctx *client_ctx, u32 start);
u32 vid_enc_pause_resume(struct video_client_ctx *client_ctx, u32 pause);
u32 vid_enc_flush(struct video_client_ctx *client_ctx,
struct venc_bufferflush *bufferflush);
u32 vid_enc_get_buffer_req(struct video_client_ctx *client_ctx,
struct venc_allocatorproperty *venc_buf_req, u32 input_dir);
u32 vid_enc_set_buffer_req(struct video_client_ctx *client_ctx,
struct venc_allocatorproperty *venc_buf_req, u32 input_dir);
u32 vid_enc_set_buffer(struct video_client_ctx *client_ctx,
struct venc_bufferpayload *buffer_info,
enum venc_buffer_dir buffer);
u32 vid_enc_free_buffer(struct video_client_ctx *client_ctx,
struct venc_bufferpayload *buffer_info,
enum venc_buffer_dir buffer);
u32 vid_enc_encode_frame(struct video_client_ctx *client_ctx,
struct venc_buffer *input_frame_info);
u32 vid_enc_fill_output_buffer(struct video_client_ctx *client_ctx,
struct venc_buffer *output_frame_info);
u32 vid_enc_set_recon_buffers(struct video_client_ctx *client_ctx,
struct venc_recon_addr *venc_recon);
u32 vid_enc_free_recon_buffers(struct video_client_ctx *client_ctx,
struct venc_recon_addr *venc_recon);
u32 vid_enc_get_recon_buffer_size(struct video_client_ctx *client_ctx,
struct venc_recon_buff_size *venc_recon_size);
u32 vid_enc_set_get_ltrmode(struct video_client_ctx *client_ctx,
struct venc_ltrmode *encoder_ltrmode, u32 set_flag);
u32 vid_enc_set_get_ltrcount(struct video_client_ctx *client_ctx,
struct venc_ltrcount *encoder_ltrcount, u32 set_flag);
u32 vid_enc_set_get_ltrperiod(struct video_client_ctx *client_ctx,
struct venc_ltrperiod *encoder_ltrperiod, u32 set_flag);
u32 vid_enc_get_capability_ltrcount(struct video_client_ctx *client_ctx,
struct venc_range *venc_capltrcount);
u32 vid_enc_set_get_ltruse(struct video_client_ctx *client_ctx,
struct venc_ltruse *encoder_ltruse, u32 set_flag);
#endif
@@ -0,0 +1,898 @@
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <mach/clk.h>
#include <linux/pm_runtime.h>
#include <mach/iommu_domains.h>
#include <media/msm/vcd_api.h>
#include <media/msm/vidc_init.h>
#include "vidc_init_internal.h"
#include "vcd_res_tracker_api.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...)
#endif
#define VIDC_NAME "msm_vidc_reg"
#define ERR(x...) printk(KERN_ERR x)
static struct vidc_dev *vidc_device_p;
static dev_t vidc_dev_num;
static struct class *vidc_class;
static const struct file_operations vidc_fops = {
.owner = THIS_MODULE,
.open = NULL,
.release = NULL,
.unlocked_ioctl = NULL,
};
struct workqueue_struct *vidc_wq;
struct workqueue_struct *vidc_timer_wq;
static irqreturn_t vidc_isr(int irq, void *dev);
static spinlock_t vidc_spin_lock;
u32 vidc_msg_timing, vidc_msg_pmem, vidc_msg_register;
#ifdef VIDC_ENABLE_DBGFS
struct dentry *vidc_debugfs_root;
struct dentry *vidc_get_debugfs_root(void)
{
if (vidc_debugfs_root == NULL)
vidc_debugfs_root = debugfs_create_dir("vidc", NULL);
return vidc_debugfs_root;
}
void vidc_debugfs_file_create(struct dentry *root, const char *name,
u32 *var)
{
struct dentry *vidc_debugfs_file =
debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var);
if (!vidc_debugfs_file)
ERR("%s(): Error creating/opening file %s\n", __func__, name);
}
#endif
static void vidc_timer_fn(unsigned long data)
{
unsigned long flag;
struct vidc_timer *hw_timer = NULL;
ERR("%s() Timer expired\n", __func__);
spin_lock_irqsave(&vidc_spin_lock, flag);
hw_timer = (struct vidc_timer *)data;
list_add_tail(&hw_timer->list, &vidc_device_p->vidc_timer_queue);
spin_unlock_irqrestore(&vidc_spin_lock, flag);
DBG("Queue the work for timer\n");
queue_work(vidc_timer_wq, &vidc_device_p->vidc_timer_worker);
}
static void vidc_timer_handler(struct work_struct *work)
{
unsigned long flag = 0;
u32 islist_empty = 0;
struct vidc_timer *hw_timer = NULL;
ERR("%s() Timer expired\n", __func__);
do {
spin_lock_irqsave(&vidc_spin_lock, flag);
islist_empty = list_empty(&vidc_device_p->vidc_timer_queue);
if (!islist_empty) {
hw_timer = list_first_entry(
&vidc_device_p->vidc_timer_queue,
struct vidc_timer, list);
list_del(&hw_timer->list);
}
spin_unlock_irqrestore(&vidc_spin_lock, flag);
if (!islist_empty && hw_timer && hw_timer->cb_func)
hw_timer->cb_func(hw_timer->userdata);
} while (!islist_empty);
}
static void vidc_work_handler(struct work_struct *work)
{
DBG("vidc_work_handler()");
vcd_read_and_clear_interrupt();
vcd_response_handler();
enable_irq(vidc_device_p->irq);
DBG("vidc_work_handler() done");
}
static DECLARE_WORK(vidc_work, vidc_work_handler);
static int __devinit vidc_720p_probe(struct platform_device *pdev)
{
struct resource *resource;
DBG("Enter %s()\n", __func__);
if (pdev->id) {
ERR("Invalid plaform device ID = %d\n", pdev->id);
return -EINVAL;
}
vidc_device_p->irq = platform_get_irq(pdev, 0);
if (unlikely(vidc_device_p->irq < 0)) {
ERR("%s(): Invalid irq = %d\n", __func__,
vidc_device_p->irq);
return -ENXIO;
}
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!resource)) {
ERR("%s(): Invalid resource\n", __func__);
return -ENXIO;
}
vidc_device_p->phys_base = resource->start;
vidc_device_p->virt_base = ioremap(resource->start,
resource->end - resource->start + 1);
if (!vidc_device_p->virt_base) {
ERR("%s() : ioremap failed\n", __func__);
return -ENOMEM;
}
vidc_device_p->device = &pdev->dev;
mutex_init(&vidc_device_p->lock);
vidc_wq = create_singlethread_workqueue("vidc_worker_queue");
if (!vidc_wq) {
ERR("%s: create workque failed\n", __func__);
return -ENOMEM;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
}
static int __devexit vidc_720p_remove(struct platform_device *pdev)
{
if (pdev->id) {
ERR("Invalid plaform device ID = %d\n", pdev->id);
return -EINVAL;
}
pm_runtime_disable(&pdev->dev);
return 0;
}
static int vidc_runtime_suspend(struct device *dev)
{
dev_dbg(dev, "pm_runtime: suspending...\n");
return 0;
}
static int vidc_runtime_resume(struct device *dev)
{
dev_dbg(dev, "pm_runtime: resuming...\n");
return 0;
}
static const struct dev_pm_ops vidc_dev_pm_ops = {
.runtime_suspend = vidc_runtime_suspend,
.runtime_resume = vidc_runtime_resume,
};
static struct platform_driver msm_vidc_720p_platform_driver = {
.probe = vidc_720p_probe,
.remove = vidc_720p_remove,
.driver = {
.name = "msm_vidc",
.pm = &vidc_dev_pm_ops,
},
};
static void __exit vidc_exit(void)
{
platform_driver_unregister(&msm_vidc_720p_platform_driver);
}
static irqreturn_t vidc_isr(int irq, void *dev)
{
DBG("\n vidc_isr() %d ", irq);
disable_irq_nosync(irq);
queue_work(vidc_wq, &vidc_work);
return IRQ_HANDLED;
}
static int __init vidc_init(void)
{
int rc = 0;
struct device *class_devp;
#ifdef VIDC_ENABLE_DBGFS
struct dentry *root = NULL;
#endif
vidc_device_p = kzalloc(sizeof(struct vidc_dev), GFP_KERNEL);
if (!vidc_device_p) {
ERR("%s Unable to allocate memory for vidc_dev\n",
__func__);
return -ENOMEM;
}
rc = alloc_chrdev_region(&vidc_dev_num, 0, 1, VIDC_NAME);
if (rc < 0) {
ERR("%s: alloc_chrdev_region Failed rc = %d\n",
__func__, rc);
goto error_vidc_alloc_chrdev_region;
}
vidc_class = class_create(THIS_MODULE, VIDC_NAME);
if (IS_ERR(vidc_class)) {
rc = PTR_ERR(vidc_class);
ERR("%s: couldn't create vidc_class rc = %d\n",
__func__, rc);
goto error_vidc_class_create;
}
class_devp = device_create(vidc_class, NULL, vidc_dev_num, NULL,
VIDC_NAME);
if (IS_ERR(class_devp)) {
rc = PTR_ERR(class_devp);
ERR("%s: class device_create failed %d\n",
__func__, rc);
goto error_vidc_class_device_create;
}
cdev_init(&vidc_device_p->cdev, &vidc_fops);
vidc_device_p->cdev.owner = THIS_MODULE;
rc = cdev_add(&(vidc_device_p->cdev), vidc_dev_num, 1);
if (rc < 0) {
ERR("%s: cdev_add failed %d\n", __func__, rc);
goto error_vidc_cdev_add;
}
rc = platform_driver_register(&msm_vidc_720p_platform_driver);
if (rc) {
ERR("%s failed to load\n", __func__);
goto error_vidc_platfom_register;
}
rc = request_irq(vidc_device_p->irq, vidc_isr, IRQF_TRIGGER_HIGH,
"vidc", vidc_device_p->device);
if (unlikely(rc)) {
ERR("%s() :request_irq failed\n", __func__);
goto error_vidc_request_irq;
}
res_trk_init(vidc_device_p->device, vidc_device_p->irq);
vidc_timer_wq = create_singlethread_workqueue("vidc_timer_wq");
if (!vidc_timer_wq) {
ERR("%s: create workque failed\n", __func__);
rc = -ENOMEM;
goto error_vidc_create_workqueue;
}
DBG("Disabling IRQ in %s()\n", __func__);
disable_irq_nosync(vidc_device_p->irq);
INIT_WORK(&vidc_device_p->vidc_timer_worker,
vidc_timer_handler);
spin_lock_init(&vidc_spin_lock);
INIT_LIST_HEAD(&vidc_device_p->vidc_timer_queue);
vidc_device_p->ref_count = 0;
vidc_device_p->firmware_refcount = 0;
vidc_device_p->get_firmware = 0;
#ifdef VIDC_ENABLE_DBGFS
root = vidc_get_debugfs_root();
if (root) {
vidc_debugfs_file_create(root, "vidc_msg_timing",
(u32 *) &vidc_msg_timing);
vidc_debugfs_file_create(root, "vidc_msg_pmem",
(u32 *) &vidc_msg_pmem);
vidc_debugfs_file_create(root, "vidc_msg_register",
(u32 *) &vidc_msg_register);
}
#endif
return 0;
error_vidc_create_workqueue:
free_irq(vidc_device_p->irq, vidc_device_p->device);
error_vidc_request_irq:
platform_driver_unregister(&msm_vidc_720p_platform_driver);
error_vidc_platfom_register:
cdev_del(&(vidc_device_p->cdev));
error_vidc_cdev_add:
device_destroy(vidc_class, vidc_dev_num);
error_vidc_class_device_create:
class_destroy(vidc_class);
error_vidc_class_create:
unregister_chrdev_region(vidc_dev_num, 1);
error_vidc_alloc_chrdev_region:
kfree(vidc_device_p);
return rc;
}
void __iomem *vidc_get_ioaddr(void)
{
return (u8 *)vidc_device_p->virt_base;
}
EXPORT_SYMBOL(vidc_get_ioaddr);
int vidc_load_firmware(void)
{
u32 status = true;
if (!res_trk_check_for_sec_session()) {
mutex_lock(&vidc_device_p->lock);
if (!vidc_device_p->get_firmware) {
status = res_trk_download_firmware();
if (!status)
goto error;
vidc_device_p->get_firmware = 1;
}
vidc_device_p->firmware_refcount++;
error:
mutex_unlock(&vidc_device_p->lock);
}
return status;
}
EXPORT_SYMBOL(vidc_load_firmware);
void vidc_release_firmware(void)
{
if (!res_trk_check_for_sec_session()) {
mutex_lock(&vidc_device_p->lock);
if (vidc_device_p->firmware_refcount > 0)
vidc_device_p->firmware_refcount--;
else
vidc_device_p->firmware_refcount = 0;
mutex_unlock(&vidc_device_p->lock);
}
}
EXPORT_SYMBOL(vidc_release_firmware);
u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
enum buffer_dir buffer, int pmem_fd,
unsigned long kvaddr, int index,
struct ion_handle **buff_handle)
{
struct buf_addr_table *buf_addr_table;
u32 rc = 0;
if (!client_ctx)
return false;
if (buffer == BUFFER_TYPE_INPUT)
buf_addr_table = client_ctx->input_buf_addr_table;
else
buf_addr_table = client_ctx->output_buf_addr_table;
if (buf_addr_table[index].pmem_fd == pmem_fd) {
if (buf_addr_table[index].kernel_vaddr == kvaddr) {
rc = buf_addr_table[index].buff_ion_flag;
*buff_handle = buf_addr_table[index].buff_ion_handle;
} else
*buff_handle = NULL;
} else
*buff_handle = NULL;
return rc;
}
EXPORT_SYMBOL(vidc_get_fd_info);
void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer)
{
u32 *num_of_buffers = NULL;
u32 i = 0;
struct buf_addr_table *buf_addr_table;
if (buffer == BUFFER_TYPE_INPUT) {
buf_addr_table = client_ctx->input_buf_addr_table;
num_of_buffers = &client_ctx->num_of_input_buffers;
DBG("%s(): buffer = INPUT\n", __func__);
} else {
buf_addr_table = client_ctx->output_buf_addr_table;
num_of_buffers = &client_ctx->num_of_output_buffers;
DBG("%s(): buffer = OUTPUT\n", __func__);
}
if (!*num_of_buffers)
goto bail_out_cleanup;
if (!client_ctx->user_ion_client)
goto bail_out_cleanup;
for (i = 0; i < *num_of_buffers; ++i) {
if (!IS_ERR_OR_NULL(buf_addr_table[i].buff_ion_handle)) {
if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle);
if (!res_trk_check_for_sec_session() &&
(res_trk_get_core_type() !=
(u32)VCD_CORE_720P)) {
ion_unmap_iommu(
client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
}
ion_free(client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle);
buf_addr_table[i].buff_ion_handle = NULL;
}
}
}
if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
if (!res_trk_check_for_sec_session() &&
(res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
}
ion_free(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
client_ctx->h264_mv_ion_handle = NULL;
}
}
bail_out_cleanup:
return;
}
EXPORT_SYMBOL(vidc_cleanup_addr_table);
u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer,
u32 search_with_user_vaddr,
unsigned long *user_vaddr,
unsigned long *kernel_vaddr,
unsigned long *phy_addr, int *pmem_fd,
struct file **file, s32 *buffer_index)
{
u32 num_of_buffers;
u32 i;
struct buf_addr_table *buf_addr_table;
u32 found = false;
if (!client_ctx)
return false;
mutex_lock(&client_ctx->enrty_queue_lock);
if (buffer == BUFFER_TYPE_INPUT) {
buf_addr_table = client_ctx->input_buf_addr_table;
num_of_buffers = client_ctx->num_of_input_buffers;
DBG("%s(): buffer = INPUT\n", __func__);
} else {
buf_addr_table = client_ctx->output_buf_addr_table;
num_of_buffers = client_ctx->num_of_output_buffers;
DBG("%s(): buffer = OUTPUT\n", __func__);
}
for (i = 0; i < num_of_buffers; ++i) {
if (search_with_user_vaddr) {
if (*user_vaddr == buf_addr_table[i].user_vaddr) {
*kernel_vaddr = buf_addr_table[i].kernel_vaddr;
found = true;
DBG("%s() : client_ctx = %p."
" user_virt_addr = 0x%08lx is found",
__func__, client_ctx, *user_vaddr);
break;
}
} else {
if (*kernel_vaddr == buf_addr_table[i].kernel_vaddr) {
*user_vaddr = buf_addr_table[i].user_vaddr;
found = true;
DBG("%s() : client_ctx = %p."
" kernel_virt_addr = 0x%08lx is found",
__func__, client_ctx, *kernel_vaddr);
break;
}
}
}
if (found) {
*phy_addr = buf_addr_table[i].dev_addr;
*pmem_fd = buf_addr_table[i].pmem_fd;
*file = buf_addr_table[i].file;
*buffer_index = i;
if (search_with_user_vaddr)
DBG("kernel_vaddr = 0x%08lx, phy_addr = 0x%08lx "
" pmem_fd = %d, struct *file = %p "
"buffer_index = %d\n", *kernel_vaddr,
*phy_addr, *pmem_fd, *file, *buffer_index);
else
DBG("user_vaddr = 0x%08lx, phy_addr = 0x%08lx "
" pmem_fd = %d, struct *file = %p "
"buffer_index = %d\n", *user_vaddr, *phy_addr,
*pmem_fd, *file, *buffer_index);
mutex_unlock(&client_ctx->enrty_queue_lock);
return true;
} else {
if (search_with_user_vaddr)
DBG("%s() : client_ctx = %p user_virt_addr = 0x%08lx"
" Not Found.\n", __func__, client_ctx, *user_vaddr);
else
DBG("%s() : client_ctx = %p kernel_virt_addr = 0x%08lx"
" Not Found.\n", __func__, client_ctx,
*kernel_vaddr);
mutex_unlock(&client_ctx->enrty_queue_lock);
return false;
}
}
EXPORT_SYMBOL(vidc_lookup_addr_table);
u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer, unsigned long user_vaddr,
unsigned long *kernel_vaddr, int pmem_fd,
unsigned long buffer_addr_offset, unsigned int max_num_buffers,
unsigned long length)
{
unsigned long len, phys_addr;
struct file *file = NULL;
u32 *num_of_buffers = NULL;
u32 i;
struct buf_addr_table *buf_addr_table;
struct ion_handle *buff_ion_handle = NULL;
unsigned long ionflag = 0;
unsigned long iova = 0;
int ret = 0;
unsigned long buffer_size = 0;
size_t ion_len;
if (!client_ctx || !length)
return false;
mutex_lock(&client_ctx->enrty_queue_lock);
if (buffer == BUFFER_TYPE_INPUT) {
buf_addr_table = client_ctx->input_buf_addr_table;
num_of_buffers = &client_ctx->num_of_input_buffers;
DBG("%s(): buffer = INPUT #Buf = %d\n",
__func__, *num_of_buffers);
} else {
buf_addr_table = client_ctx->output_buf_addr_table;
num_of_buffers = &client_ctx->num_of_output_buffers;
DBG("%s(): buffer = OUTPUT #Buf = %d\n",
__func__, *num_of_buffers);
length = length * 2; /* workaround for iommu video h/w bug */
}
if (*num_of_buffers == max_num_buffers) {
ERR("%s(): Num of buffers reached max value : %d",
__func__, max_num_buffers);
goto bail_out_add;
}
i = 0;
while (i < *num_of_buffers &&
user_vaddr != buf_addr_table[i].user_vaddr)
i++;
if (i < *num_of_buffers) {
DBG("%s() : client_ctx = %p."
" user_virt_addr = 0x%08lx already set",
__func__, client_ctx, user_vaddr);
goto bail_out_add;
} else {
if (!vcd_get_ion_status()) {
pr_err("PMEM not available\n");
goto bail_out_add;
} else {
buff_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client, pmem_fd);
if (IS_ERR_OR_NULL(buff_ion_handle)) {
ERR("%s(): get_ION_handle failed\n",
__func__);
goto bail_out_add;
}
if (ion_handle_get_flags(client_ctx->user_ion_client,
buff_ion_handle,
&ionflag)) {
ERR("%s():ION flags fail\n",
__func__);
goto bail_out_add;
}
*kernel_vaddr = (unsigned long)
ion_map_kernel(
client_ctx->user_ion_client,
buff_ion_handle);
if (IS_ERR_OR_NULL((void *)*kernel_vaddr)) {
ERR("%s():ION virtual addr fail\n",
__func__);
*kernel_vaddr = (unsigned long)NULL;
goto ion_free_error;
}
if (res_trk_check_for_sec_session() ||
(res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
if (ion_phys(client_ctx->user_ion_client,
buff_ion_handle,
&phys_addr, &ion_len)) {
ERR("%s():ION physical addr fail\n",
__func__);
goto ion_map_error;
}
len = (unsigned long) ion_len;
buf_addr_table[*num_of_buffers].client_data =
NULL;
buf_addr_table[*num_of_buffers].dev_addr =
phys_addr;
} else {
ret = ion_map_iommu(client_ctx->user_ion_client,
buff_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL,
SZ_8K,
length,
(unsigned long *) &iova,
(unsigned long *) &buffer_size,
0,
ION_IOMMU_UNMAP_DELAYED);
if (ret || !iova) {
ERR(
"%s():ION iommu map fail, ret = %d, iova = 0x%lx\n",
__func__, ret, iova);
goto ion_map_error;
}
phys_addr = iova;
buf_addr_table[*num_of_buffers].client_data =
NULL;
buf_addr_table[*num_of_buffers].dev_addr =
iova;
}
}
phys_addr += buffer_addr_offset;
(*kernel_vaddr) += buffer_addr_offset;
buf_addr_table[*num_of_buffers].user_vaddr = user_vaddr;
buf_addr_table[*num_of_buffers].kernel_vaddr = *kernel_vaddr;
buf_addr_table[*num_of_buffers].pmem_fd = pmem_fd;
buf_addr_table[*num_of_buffers].file = file;
buf_addr_table[*num_of_buffers].phy_addr = phys_addr;
buf_addr_table[*num_of_buffers].buff_ion_handle =
buff_ion_handle;
buf_addr_table[*num_of_buffers].buff_ion_flag =
ionflag;
*num_of_buffers = *num_of_buffers + 1;
DBG("%s() : client_ctx = %p, user_virt_addr = 0x%08lx, "
"kernel_vaddr = 0x%08lx phys_addr=%lu inserted!",
__func__, client_ctx, user_vaddr, *kernel_vaddr,
phys_addr);
}
mutex_unlock(&client_ctx->enrty_queue_lock);
return true;
ion_map_error:
if (*kernel_vaddr && buff_ion_handle)
ion_unmap_kernel(client_ctx->user_ion_client, buff_ion_handle);
ion_free_error:
if (!IS_ERR_OR_NULL(buff_ion_handle))
ion_free(client_ctx->user_ion_client, buff_ion_handle);
bail_out_add:
mutex_unlock(&client_ctx->enrty_queue_lock);
return false;
}
EXPORT_SYMBOL(vidc_insert_addr_table);
/*
* Similar to vidc_insert_addr_table except intended for in-kernel
* use where buffers have already been alloced and mapped properly
*/
u32 vidc_insert_addr_table_kernel(struct video_client_ctx *client_ctx,
enum buffer_dir buffer, unsigned long user_vaddr,
unsigned long kernel_vaddr, unsigned long phys_addr,
unsigned int max_num_buffers,
unsigned long length)
{
u32 *num_of_buffers = NULL;
u32 i;
struct buf_addr_table *buf_addr_table;
struct msm_mapped_buffer *mapped_buffer = NULL;
if (!client_ctx || !length || !kernel_vaddr || !phys_addr)
return false;
mutex_lock(&client_ctx->enrty_queue_lock);
if (buffer == BUFFER_TYPE_INPUT) {
buf_addr_table = client_ctx->input_buf_addr_table;
num_of_buffers = &client_ctx->num_of_input_buffers;
DBG("%s(): buffer = INPUT #Buf = %d\n",
__func__, *num_of_buffers);
} else {
buf_addr_table = client_ctx->output_buf_addr_table;
num_of_buffers = &client_ctx->num_of_output_buffers;
DBG("%s(): buffer = OUTPUT #Buf = %d\n",
__func__, *num_of_buffers);
}
if (*num_of_buffers == max_num_buffers) {
ERR("%s(): Num of buffers reached max value : %d",
__func__, max_num_buffers);
goto bail_out_add;
}
i = 0;
while (i < *num_of_buffers &&
user_vaddr != buf_addr_table[i].user_vaddr) {
i++;
}
if (i < *num_of_buffers) {
DBG("%s() : client_ctx = %p."
" user_virt_addr = 0x%08lx already set",
__func__, client_ctx, user_vaddr);
goto bail_out_add;
} else {
mapped_buffer = NULL;
buf_addr_table[*num_of_buffers].client_data = (void *)
mapped_buffer;
buf_addr_table[*num_of_buffers].dev_addr = phys_addr;
buf_addr_table[*num_of_buffers].user_vaddr = user_vaddr;
buf_addr_table[*num_of_buffers].kernel_vaddr = kernel_vaddr;
buf_addr_table[*num_of_buffers].pmem_fd = -1;
buf_addr_table[*num_of_buffers].file = NULL;
buf_addr_table[*num_of_buffers].phy_addr = phys_addr;
buf_addr_table[*num_of_buffers].buff_ion_handle = NULL;
*num_of_buffers = *num_of_buffers + 1;
DBG("%s() : client_ctx = %p, user_virt_addr = 0x%08lx, "
"kernel_vaddr = 0x%08lx inserted!", __func__,
client_ctx, user_vaddr, kernel_vaddr);
}
mutex_unlock(&client_ctx->enrty_queue_lock);
return true;
bail_out_add:
mutex_unlock(&client_ctx->enrty_queue_lock);
return false;
}
EXPORT_SYMBOL(vidc_insert_addr_table_kernel);
u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer,
unsigned long user_vaddr,
unsigned long *kernel_vaddr)
{
u32 *num_of_buffers = NULL;
u32 i;
struct buf_addr_table *buf_addr_table;
if (!client_ctx)
return false;
mutex_lock(&client_ctx->enrty_queue_lock);
if (buffer == BUFFER_TYPE_INPUT) {
buf_addr_table = client_ctx->input_buf_addr_table;
num_of_buffers = &client_ctx->num_of_input_buffers;
} else {
buf_addr_table = client_ctx->output_buf_addr_table;
num_of_buffers = &client_ctx->num_of_output_buffers;
}
if (!*num_of_buffers)
goto bail_out_del;
i = 0;
while (i < *num_of_buffers &&
user_vaddr != buf_addr_table[i].user_vaddr)
i++;
if (i == *num_of_buffers) {
pr_err("%s() : client_ctx = %p."
" user_virt_addr = 0x%08lx NOT found",
__func__, client_ctx, user_vaddr);
goto bail_out_del;
}
*kernel_vaddr = buf_addr_table[i].kernel_vaddr;
if (buf_addr_table[i].buff_ion_handle) {
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle);
if (!res_trk_check_for_sec_session() &&
(res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
}
ion_free(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle);
buf_addr_table[i].buff_ion_handle = NULL;
}
if (i < (*num_of_buffers - 1)) {
buf_addr_table[i].client_data =
buf_addr_table[*num_of_buffers - 1].client_data;
buf_addr_table[i].dev_addr =
buf_addr_table[*num_of_buffers - 1].dev_addr;
buf_addr_table[i].user_vaddr =
buf_addr_table[*num_of_buffers - 1].user_vaddr;
buf_addr_table[i].kernel_vaddr =
buf_addr_table[*num_of_buffers - 1].kernel_vaddr;
buf_addr_table[i].phy_addr =
buf_addr_table[*num_of_buffers - 1].phy_addr;
buf_addr_table[i].pmem_fd =
buf_addr_table[*num_of_buffers - 1].pmem_fd;
buf_addr_table[i].file =
buf_addr_table[*num_of_buffers - 1].file;
buf_addr_table[i].buff_ion_handle =
buf_addr_table[*num_of_buffers - 1].buff_ion_handle;
}
*num_of_buffers = *num_of_buffers - 1;
DBG("%s() : client_ctx = %p."
" user_virt_addr = 0x%08lx is found and deleted",
__func__, client_ctx, user_vaddr);
mutex_unlock(&client_ctx->enrty_queue_lock);
return true;
bail_out_del:
mutex_unlock(&client_ctx->enrty_queue_lock);
return false;
}
EXPORT_SYMBOL(vidc_delete_addr_table);
u32 vidc_timer_create(void (*timer_handler)(void *),
void *user_data, void **timer_handle)
{
struct vidc_timer *hw_timer = NULL;
if (!timer_handler || !timer_handle) {
DBG("%s(): timer creation failed\n ", __func__);
return false;
}
hw_timer = kzalloc(sizeof(struct vidc_timer), GFP_KERNEL);
if (!hw_timer) {
DBG("%s(): timer creation failed in allocation\n ", __func__);
return false;
}
init_timer(&hw_timer->hw_timeout);
hw_timer->hw_timeout.data = (unsigned long)hw_timer;
hw_timer->hw_timeout.function = vidc_timer_fn;
hw_timer->cb_func = timer_handler;
hw_timer->userdata = user_data;
*timer_handle = hw_timer;
return true;
}
EXPORT_SYMBOL(vidc_timer_create);
void vidc_timer_release(void *timer_handle)
{
kfree(timer_handle);
}
EXPORT_SYMBOL(vidc_timer_release);
void vidc_timer_start(void *timer_handle, u32 time_out)
{
struct vidc_timer *hw_timer = (struct vidc_timer *)timer_handle;
DBG("%s(): start timer\n ", __func__);
if (hw_timer) {
hw_timer->hw_timeout.expires = jiffies + 1*HZ;
add_timer(&hw_timer->hw_timeout);
}
}
EXPORT_SYMBOL(vidc_timer_start);
void vidc_timer_stop(void *timer_handle)
{
struct vidc_timer *hw_timer = (struct vidc_timer *)timer_handle;
DBG("%s(): stop timer\n ", __func__);
if (hw_timer)
del_timer(&hw_timer->hw_timeout);
}
EXPORT_SYMBOL(vidc_timer_stop);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Video decoder/encoder driver Init Module");
MODULE_VERSION("1.0");
module_init(vidc_init);
module_exit(vidc_exit);
@@ -0,0 +1,41 @@
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef VIDC_INIT_INTERNAL_H
#define VIDC_INIT_INTERNAL_H
#include <linux/cdev.h>
struct vidc_timer {
struct list_head list;
struct timer_list hw_timeout;
void (*cb_func)(void *);
void *userdata;
};
struct vidc_dev {
struct cdev cdev;
struct device *device;
resource_size_t phys_base;
void __iomem *virt_base;
unsigned int irq;
unsigned int ref_count;
unsigned int firmware_refcount;
unsigned int get_firmware;
struct mutex lock;
s32 device_handle;
struct list_head vidc_timer_queue;
struct work_struct vidc_timer_worker;
};
#endif
@@ -0,0 +1,408 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_H_
#define _VCD_H_
#include <media/msm/vcd_api.h>
#include "vcd_util.h"
#include "vcd_ddl_api.h"
#include "vcd_res_tracker_api.h"
#include "vcd_client_sm.h"
#include "vcd_core.h"
#include "vcd_device_sm.h"
void vcd_reset_device_channels(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_get_command_channel
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc **transc);
u32 vcd_get_command_channel_in_loop
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc **transc);
void vcd_mark_command_channel
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
void vcd_release_command_channel
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
void vcd_release_multiple_command_channels(struct vcd_dev_ctxt *dev_ctxt,
u32 channels);
void vcd_release_interim_command_channels(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_get_frame_channel
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc **transc);
u32 vcd_get_frame_channel_in_loop
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc **transc);
void vcd_mark_frame_channel(struct vcd_dev_ctxt *dev_ctxt);
void vcd_release_frame_channel
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
void vcd_release_multiple_frame_channels(struct vcd_dev_ctxt *dev_ctxt,
u32 channels);
void vcd_release_interim_frame_channels(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_core_is_busy(struct vcd_dev_ctxt *dev_ctxt);
void vcd_device_timer_start(struct vcd_dev_ctxt *dev_ctxt);
void vcd_device_timer_stop(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_init_device_context
(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code);
u32 vcd_deinit_device_context
(struct vcd_drv_ctxt *drv_ctxt, u32 ev_code);
u32 vcd_init_client_context(struct vcd_clnt_ctxt *cctxt);
void vcd_destroy_client_context(struct vcd_clnt_ctxt *cctxt);
u32 vcd_check_for_client_context
(struct vcd_dev_ctxt *dev_ctxt, s32 driver_id);
u32 vcd_validate_driver_handle
(struct vcd_dev_ctxt *dev_ctxt, s32 driver_handle);
void vcd_handle_for_last_clnt_close
(struct vcd_dev_ctxt *dev_ctxt, u32 send_deinit);
u32 vcd_common_allocate_set_buffer
(struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer,
u32 buf_size, struct vcd_buffer_pool **buf_pool);
u32 vcd_set_buffer_internal
(struct vcd_clnt_ctxt *cctxt,
struct vcd_buffer_pool *buf_pool, u8 *buffer, u32 buf_size);
u32 vcd_allocate_buffer_internal
(struct vcd_clnt_ctxt *cctxt,
struct vcd_buffer_pool *buf_pool,
u32 buf_size, u8 **vir_buf_addr, u8 **phy_buf_addr);
u32 vcd_free_one_buffer_internal
(struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer_type, u8 *buffer);
u32 vcd_free_buffers_internal
(struct vcd_clnt_ctxt *cctxt,
struct vcd_buffer_pool *buf_pool);
u32 vcd_alloc_buffer_pool_entries
(struct vcd_buffer_pool *buf_pool,
struct vcd_buffer_requirement *buf_req);
void vcd_free_buffer_pool_entries(struct vcd_buffer_pool *buf_pool);
void vcd_flush_in_use_buffer_pool_entries(struct vcd_clnt_ctxt *cctxt,
struct vcd_buffer_pool *buf_pool, u32 event);
void vcd_reset_buffer_pool_for_reuse(struct vcd_buffer_pool *buf_pool);
struct vcd_buffer_entry *vcd_get_free_buffer_pool_entry
(struct vcd_buffer_pool *pool);
struct vcd_buffer_entry *vcd_find_buffer_pool_entry
(struct vcd_buffer_pool *pool, u8 *v_addr);
struct vcd_buffer_entry *vcd_buffer_pool_entry_de_q
(struct vcd_buffer_pool *pool);
u32 vcd_buffer_pool_entry_en_q
(struct vcd_buffer_pool *pool,
struct vcd_buffer_entry *entry);
u32 vcd_check_if_buffer_req_met(struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer_type);
u32 vcd_client_cmd_en_q
(struct vcd_clnt_ctxt *cctxt, enum vcd_command command);
void vcd_client_cmd_flush_and_en_q
(struct vcd_clnt_ctxt *cctxt, enum vcd_command command);
u32 vcd_client_cmd_de_q
(struct vcd_clnt_ctxt *cctxt, enum vcd_command *command);
u32 vcd_handle_recvd_eos
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame, u32 * pb_eos_handled);
u32 vcd_handle_first_decode_frame(struct vcd_clnt_ctxt *cctxt);
u32 vcd_handle_input_frame
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame);
u32 vcd_store_seq_hdr
(struct vcd_clnt_ctxt *cctxt,
struct vcd_sequence_hdr *seq_hdr);
u32 vcd_set_frame_size
(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_frame_size *frm_size);
u32 vcd_set_frame_rate
(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_frame_rate *fps);
u32 vcd_calculate_frame_delta
(struct vcd_clnt_ctxt *cctxt, struct vcd_frame_data *frame);
struct vcd_buffer_entry *vcd_check_fill_output_buffer
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *buffer);
u32 vcd_handle_first_fill_output_buffer
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *buffer, u32 *b_handled);
u32 vcd_handle_first_fill_output_buffer_for_enc
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *frm_entry, u32 *b_handled);
u32 vcd_handle_first_fill_output_buffer_for_dec
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *frm_entry, u32 *b_handled);
u32 vcd_schedule_frame(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt **cctxt, struct vcd_buffer_entry
**ip_buf_entry);
u32 vcd_submit_command_in_continue
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
u32 vcd_submit_cmd_sess_start(struct vcd_transc *transc);
u32 vcd_submit_cmd_sess_end(struct vcd_transc *transc);
void vcd_submit_cmd_client_close(struct vcd_clnt_ctxt *cctxt);
u32 vcd_submit_frame
(struct vcd_dev_ctxt *dev_ctxt, struct vcd_transc *transc);
u32 vcd_try_submit_frame_in_continue(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_transc *transc);
u32 vcd_process_cmd_sess_start(struct vcd_clnt_ctxt *cctxt);
void vcd_try_submit_frame(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_setup_with_ddl_capabilities(struct vcd_dev_ctxt *dev_ctxt);
void vcd_handle_submit_frame_failed(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_transc *transc);
struct vcd_transc *vcd_get_free_trans_tbl_entry
(struct vcd_dev_ctxt *dev_ctxt);
void vcd_release_trans_tbl_entry(struct vcd_transc *trans_entry);
void vcd_release_all_clnt_frm_transc(struct vcd_clnt_ctxt *cctxt);
void vcd_release_all_clnt_transc(struct vcd_clnt_ctxt *cctxt);
u32 vcd_handle_input_done
(struct vcd_clnt_ctxt *cctxt,
void *payload, u32 event, u32 status);
u32 vcd_handle_input_done_in_eos
(struct vcd_clnt_ctxt *cctxt, void *payload, u32 status);
void vcd_handle_input_done_failed
(struct vcd_clnt_ctxt *cctxt, struct vcd_transc *transc);
void vcd_handle_input_done_with_codec_config
(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc,
struct ddl_frame_data_tag *frm);
void vcd_handle_input_done_for_interlacing
(struct vcd_clnt_ctxt *cctxt);
void vcd_handle_input_done_with_trans_end
(struct vcd_clnt_ctxt *cctxt);
u32 vcd_handle_frame_done
(struct vcd_clnt_ctxt *cctxt,
void *payload, u32 event, u32 status);
void vcd_handle_frame_done_for_interlacing
(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc_ip1,
struct ddl_frame_data_tag *op_frm, u32 status);
u32 vcd_handle_frame_done_in_eos
(struct vcd_clnt_ctxt *cctxt, void *payload, u32 status);
u32 vcd_handle_output_required(struct vcd_clnt_ctxt *cctxt,
void *payload, u32 status);
u32 vcd_handle_output_required_in_flushing(struct vcd_clnt_ctxt *cctxt,
void *payload);
u32 vcd_handle_output_req_tran_end_in_eos(struct vcd_clnt_ctxt *cctxt);
u32 vcd_validate_io_done_pyld
(struct vcd_clnt_ctxt *cctxt, void *payload, u32 status);
void vcd_handle_eos_trans_end(struct vcd_clnt_ctxt *cctxt);
void vcd_handle_eos_done
(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc, u32 status);
void vcd_send_frame_done_in_eos
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame, u32 valid_opbuf);
void vcd_send_frame_done_in_eos_for_dec
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame);
void vcd_send_frame_done_in_eos_for_enc
(struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame);
void vcd_handle_start_done(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc, u32 status);
void vcd_handle_stop_done(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc, u32 status);
void vcd_handle_stop_done_in_starting(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc, u32 status);
void vcd_handle_stop_done_in_invalid(struct vcd_clnt_ctxt *cctxt,
struct vcd_transc *transc, u32 status);
void vcd_send_flush_done(struct vcd_clnt_ctxt *cctxt, u32 status);
void vcd_process_pending_flush_in_eos(struct vcd_clnt_ctxt *cctxt);
void vcd_process_pending_stop_in_eos(struct vcd_clnt_ctxt *cctxt);
void vcd_handle_trans_pending(struct vcd_clnt_ctxt *cctxt);
u32 vcd_handle_ind_output_reconfig
(struct vcd_clnt_ctxt *cctxt, void* payload, u32 status);
u32 vcd_handle_ind_output_reconfig_in_flushing
(struct vcd_clnt_ctxt *cctxt, void* payload, u32 status);
void vcd_flush_output_buffers(struct vcd_clnt_ctxt *cctxt);
void vcd_flush_bframe_buffers(struct vcd_clnt_ctxt *cctxt, u32 mode);
u32 vcd_flush_buffers(struct vcd_clnt_ctxt *cctxt, u32 mode);
void vcd_flush_buffers_in_err_fatal(struct vcd_clnt_ctxt *cctxt);
u32 vcd_power_event
(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt, u32 event);
u32 vcd_device_power_event(struct vcd_dev_ctxt *dev_ctxt, u32 event,
struct vcd_clnt_ctxt *cctxt);
u32 vcd_client_power_event
(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt, u32 event);
u32 vcd_enable_clock(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt);
u32 vcd_disable_clock(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_set_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
u32 vcd_update_clnt_perf_lvl
(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_frame_rate *fps, u32 frm_p_units);
u32 vcd_gate_clock(struct vcd_dev_ctxt *dev_ctxt);
u32 vcd_un_gate_clock(struct vcd_dev_ctxt *dev_ctxt);
void vcd_handle_err_fatal(struct vcd_clnt_ctxt *cctxt,
u32 event, u32 status);
void vcd_handle_device_err_fatal(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt);
void vcd_clnt_handle_device_err_fatal(struct vcd_clnt_ctxt *cctxt,
u32 event);
void vcd_handle_err_in_starting(struct vcd_clnt_ctxt *cctxt,
u32 status);
void vcd_handle_ind_hw_err_fatal(struct vcd_clnt_ctxt *cctxt,
u32 event, u32 status);
u32 vcd_return_op_buffer_to_hw(struct vcd_clnt_ctxt *cctxt,
struct vcd_buffer_entry *buf_entry);
u32 vcd_sched_create(struct list_head *sched_list);
void vcd_sched_destroy(struct list_head *sched_clnt_list);
u32 vcd_sched_add_client(struct vcd_clnt_ctxt *cctxt);
u32 vcd_sched_remove_client(struct vcd_sched_clnt_ctx *sched_cctxt);
u32 vcd_sched_update_config(struct vcd_clnt_ctxt *cctxt);
u32 vcd_sched_queue_buffer(
struct vcd_sched_clnt_ctx *sched_cctxt,
struct vcd_buffer_entry *buffer, u32 b_tail);
u32 vcd_sched_dequeue_buffer(
struct vcd_sched_clnt_ctx *sched_cctxt,
struct vcd_buffer_entry **buffer);
u32 vcd_sched_mark_client_eof(struct vcd_sched_clnt_ctx *sched_cctxt);
u32 vcd_sched_suspend_resume_clnt(
struct vcd_clnt_ctxt *cctxt, u32 b_state);
u32 vcd_sched_get_client_frame(struct list_head *sched_clnt_list,
struct vcd_clnt_ctxt **cctxt,
struct vcd_buffer_entry **buffer);
void vcd_handle_clnt_fatal(struct vcd_clnt_ctxt *cctxt, u32 trans_end);
void vcd_handle_clnt_fatal_input_done(struct vcd_clnt_ctxt *cctxt,
u32 trans_end);
void vcd_handle_ind_info_output_reconfig
(struct vcd_clnt_ctxt *cctxt, u32 status);
u32 vcd_req_perf_level(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_perf_level *);
u32 vcd_set_num_slices(struct vcd_clnt_ctxt *cctxt);
u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt);
struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
struct vcd_clnt_ctxt *cctxt);
u32 vcd_handle_ltr_use_failed(struct vcd_clnt_ctxt *cctxt,
void *payload, size_t sz, u32 status);
#endif
@@ -0,0 +1,981 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/export.h>
#include <media/msm/vidc_type.h>
#include <media/msm/vidc_init.h>
#include "vcd.h"
u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_drv_ctxt *drv_ctxt;
VCD_MSG_MED("vcd_init:");
if (!config ||
!driver_handle || !config->map_dev_base_addr) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_ILLEGAL_PARM;
}
drv_ctxt = vcd_get_drv_context();
mutex_init(&drv_ctxt->dev_mutex);
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.init) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
init(drv_ctxt, config, driver_handle);
} else {
VCD_MSG_ERROR("Unsupported API in device state %d",
drv_ctxt->dev_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_init);
u32 vcd_term(s32 driver_handle)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_drv_ctxt *drv_ctxt;
VCD_MSG_MED("vcd_term:");
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.term) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
term(drv_ctxt, driver_handle);
} else {
VCD_MSG_ERROR("Unsupported API in device state %d",
drv_ctxt->dev_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_term);
struct client_security_info {
int secure_enc;
int secure_dec;
int non_secure_enc;
int non_secure_dec;
};
static int vcd_get_clients_security_info(struct client_security_info *sec_info)
{
struct vcd_drv_ctxt *drv_ctxt;
struct vcd_clnt_ctxt *cctxt;
int count = 0;
if (!sec_info) {
VCD_MSG_ERROR("Invalid argument\n");
return -EINVAL;
}
memset(sec_info, 0 , sizeof(*sec_info));
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
while (cctxt) {
if (cctxt->secure && cctxt->decoding)
sec_info->secure_dec++;
else if (cctxt->secure && !cctxt->decoding)
sec_info->secure_enc++;
else if (!cctxt->secure && cctxt->decoding)
sec_info->non_secure_dec++;
else
sec_info->non_secure_enc++;
count++;
cctxt = cctxt->next;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return count;
}
static int is_session_invalid(u32 decoding, u32 flags)
{
int is_secure;
struct client_security_info sec_info;
int client_count = 0;
int secure_session_running = 0, non_secure_runnung = 0;
is_secure = (flags & VCD_CP_SESSION) ? 1 : 0;
client_count = vcd_get_clients_security_info(&sec_info);
secure_session_running = (sec_info.secure_enc > 0) ||
(sec_info.secure_dec > 0);
non_secure_runnung = sec_info.non_secure_dec + sec_info.non_secure_enc;
if (!is_secure) {
if (secure_session_running) {
pr_err("non secure session failed secure running\n");
return -EACCES;
}
} else {
if (non_secure_runnung) {
pr_err("Secure session failed non secure running\n");
return -EACCES;
}
}
return 0;
}
u32 vcd_open(s32 driver_handle, u32 decoding,
void (*callback) (u32 event, u32 status, void *info, size_t sz,
void *handle, void *const client_data),
void *client_data, int flags)
{
u32 rc = 0, num_of_instances = 0;
struct vcd_drv_ctxt *drv_ctxt;
struct vcd_clnt_ctxt *cctxt;
int is_secure = (flags & VCD_CP_SESSION) ? 1 : 0;
VCD_MSG_MED("vcd_open:");
if (!callback) {
VCD_MSG_ERROR("Bad parameters");
return -EINVAL;
}
drv_ctxt = vcd_get_drv_context();
cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
while (cctxt) {
num_of_instances++;
cctxt = cctxt->next;
}
if (num_of_instances == VIDC_MAX_NUM_CLIENTS) {
pr_err(" %s(): Max number of clients reached\n", __func__);
return -ENODEV;
}
rc = is_session_invalid(decoding, flags);
if (rc) {
VCD_MSG_ERROR("Invalid Session: is_decoder: %d, secure: %d\n",
decoding, flags);
return rc;
}
if (is_secure)
res_trk_secure_set();
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.open) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
open(drv_ctxt, driver_handle, decoding, callback,
client_data);
if (rc) {
rc = -ENODEV;
}
} else {
VCD_MSG_ERROR("Unsupported API in device state %d",
drv_ctxt->dev_state.state);
rc = -EPERM;
}
if (!rc) {
cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
cctxt->secure = is_secure;
} else if (is_secure)
res_trk_secure_unset();
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_open);
u32 vcd_close(void *handle)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
int is_secure = 0;
VCD_MSG_MED("vcd_close:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
is_secure = cctxt->secure;
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.close) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
close(drv_ctxt, cctxt);
} else {
VCD_MSG_ERROR("Unsupported API in device state %d",
drv_ctxt->dev_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
if (is_secure)
res_trk_secure_unset();
return rc;
}
EXPORT_SYMBOL(vcd_close);
u32 vcd_encode_start(void *handle)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_encode_start:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.encode_start &&
drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
encode_start(cctxt);
} else {
VCD_MSG_ERROR
("Unsupported API in dev power state %d OR client state %d",
drv_ctxt->dev_ctxt.pwr_state,
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_encode_start);
u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_encode_frame:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!input_frame) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.encode_frame) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
encode_frame(cctxt, input_frame);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_encode_frame);
u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_decode_start:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.decode_start &&
drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
decode_start(cctxt, seq_hdr);
} else {
VCD_MSG_ERROR
("Unsupported API in dev power state %d OR client state %d",
drv_ctxt->dev_ctxt.pwr_state,
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_decode_start);
u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_decode_frame:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!input_frame) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.decode_frame) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
decode_frame(cctxt, input_frame);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_decode_frame);
u32 vcd_pause(void *handle)
{
struct vcd_drv_ctxt *drv_ctxt;
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
u32 rc;
VCD_MSG_MED("vcd_pause:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.pause) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
pause(cctxt);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_pause);
u32 vcd_resume(void *handle)
{
struct vcd_drv_ctxt *drv_ctxt;
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
u32 rc;
VCD_MSG_MED("vcd_resume:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.resume &&
drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
resume(drv_ctxt, cctxt);
} else {
VCD_MSG_ERROR
("Unsupported API in dev power state %d OR client state %d",
drv_ctxt->dev_ctxt.pwr_state,
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_resume);
u32 vcd_flush(void *handle, u32 mode)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_flush:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.flush) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
flush(cctxt, mode);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_flush);
u32 vcd_stop(void *handle)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_stop:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.stop &&
drv_ctxt->dev_ctxt.pwr_state != VCD_PWR_STATE_SLEEP) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
stop(cctxt);
} else {
VCD_MSG_ERROR
("Unsupported API in dev power state %d OR client state %d",
drv_ctxt->dev_ctxt.pwr_state,
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_stop);
u32 vcd_set_property(void *handle,
struct vcd_property_hdr *prop_hdr, void *prop_val)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_set_property:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!prop_hdr || !prop_val) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.set_property) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
set_property(cctxt, prop_hdr, prop_val);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_set_property);
u32 vcd_get_property(void *handle,
struct vcd_property_hdr *prop_hdr, void *prop_val)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_get_property:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!prop_hdr || !prop_val) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.get_property) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
get_property(cctxt, prop_hdr, prop_val);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_get_property);
u32 vcd_set_buffer_requirements(void *handle,
enum vcd_buffer_type buffer,
struct vcd_buffer_requirement *buffer_req)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_set_buffer_requirements:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!buffer_req) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.
set_buffer_requirements) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
set_buffer_requirements(cctxt, buffer, buffer_req);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_set_buffer_requirements);
u32 vcd_get_buffer_requirements(void *handle,
enum vcd_buffer_type buffer,
struct vcd_buffer_requirement *buffer_req)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_get_buffer_requirements:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!buffer_req) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.
get_buffer_requirements) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
get_buffer_requirements(cctxt, buffer, buffer_req);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_get_buffer_requirements);
u32 vcd_set_buffer(void *handle,
enum vcd_buffer_type buffer_type, u8 *buffer, u32 buf_size)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_set_buffer:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!buffer || !buf_size) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.set_buffer) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
set_buffer(cctxt, buffer_type, buffer, buf_size);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_set_buffer);
u32 vcd_allocate_buffer(void *handle,
enum vcd_buffer_type buffer,
u32 buf_size, u8 **vir_buf_addr, u8 **phy_buf_addr)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_allocate_buffer:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!vir_buf_addr || !phy_buf_addr
|| !buf_size) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.allocate_buffer) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
allocate_buffer(cctxt, buffer, buf_size,
vir_buf_addr, phy_buf_addr);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_allocate_buffer);
u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, u8 *buffer)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_free_buffer:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.free_buffer) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
free_buffer(cctxt, buffer_type, buffer);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_free_buffer);
u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer)
{
struct vcd_clnt_ctxt *cctxt =
(struct vcd_clnt_ctxt *)handle;
struct vcd_drv_ctxt *drv_ctxt;
u32 rc;
VCD_MSG_MED("vcd_fill_output_buffer:");
if (!cctxt || cctxt->signature != VCD_SIGNATURE) {
VCD_MSG_ERROR("Bad client handle");
return VCD_ERR_BAD_HANDLE;
}
if (!buffer) {
VCD_MSG_ERROR("Bad parameters");
return VCD_ERR_BAD_POINTER;
}
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (cctxt->clnt_state.state_table->ev_hdlr.fill_output_buffer) {
rc = cctxt->clnt_state.state_table->ev_hdlr.
fill_output_buffer(cctxt, buffer);
} else {
VCD_MSG_ERROR("Unsupported API in client state %d",
cctxt->clnt_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_fill_output_buffer);
u32 vcd_set_device_power(s32 driver_handle,
enum vcd_power_state pwr_state)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_drv_ctxt *drv_ctxt;
VCD_MSG_MED("vcd_set_device_power:");
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (drv_ctxt->dev_state.state_table->ev_hdlr.set_dev_pwr) {
rc = drv_ctxt->dev_state.state_table->ev_hdlr.
set_dev_pwr(drv_ctxt, pwr_state);
} else {
VCD_MSG_ERROR("Unsupported API in device state %d",
drv_ctxt->dev_state.state);
rc = VCD_ERR_BAD_STATE;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return rc;
}
EXPORT_SYMBOL(vcd_set_device_power);
void vcd_read_and_clear_interrupt(void)
{
VCD_MSG_LOW("vcd_read_and_clear_interrupt:");
ddl_read_and_clear_interrupt();
}
void vcd_response_handler(void)
{
struct vcd_drv_ctxt *drv_ctxt;
VCD_MSG_LOW("vcd_response_handler:");
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
if (!ddl_process_core_response()) {
VCD_MSG_HIGH
("ddl_process_core_response indicated no further"
"processing");
mutex_unlock(&drv_ctxt->dev_mutex);
return;
}
if (drv_ctxt->dev_ctxt.command_continue)
vcd_continue();
mutex_unlock(&drv_ctxt->dev_mutex);
}
EXPORT_SYMBOL(vcd_response_handler);
u8 vcd_get_num_of_clients(void)
{
struct vcd_drv_ctxt *drv_ctxt;
struct vcd_clnt_ctxt *cctxt;
u8 count = 0;
VCD_MSG_LOW("vcd_get_num_of_clients:");
drv_ctxt = vcd_get_drv_context();
mutex_lock(&drv_ctxt->dev_mutex);
cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
while (cctxt) {
count++;
cctxt = cctxt->next;
}
mutex_unlock(&drv_ctxt->dev_mutex);
return count;
}
EXPORT_SYMBOL(vcd_get_num_of_clients);
u32 vcd_get_ion_status(void)
{
return res_trk_get_enable_ion();
}
EXPORT_SYMBOL(vcd_get_ion_status);
struct ion_client *vcd_get_ion_client(void)
{
return res_trk_get_ion_client();
}
EXPORT_SYMBOL(vcd_get_ion_client);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,110 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_CLIENT_SM_H_
#define _VCD_CLIENT_SM_H_
#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
struct vcd_clnt_state_table;
struct vcd_clnt_state_ctxt;
struct vcd_clnt_ctxt;
enum vcd_clnt_state_enum {
VCD_CLIENT_STATE_NULL = 0,
VCD_CLIENT_STATE_OPEN,
VCD_CLIENT_STATE_STARTING,
VCD_CLIENT_STATE_RUN,
VCD_CLIENT_STATE_FLUSHING,
VCD_CLIENT_STATE_PAUSING,
VCD_CLIENT_STATE_PAUSED,
VCD_CLIENT_STATE_STOPPING,
VCD_CLIENT_STATE_EOS,
VCD_CLIENT_STATE_INVALID,
VCD_CLIENT_STATE_MAX,
VCD_CLIENT_STATE_32BIT = 0x7FFFFFFF
};
#define CLIENT_STATE_EVENT_NUMBER(ppf) \
((u32 *) (&(((struct vcd_clnt_state_table*)0)->ev_hdlr.ppf)) - \
(u32 *) (&(((struct vcd_clnt_state_table*)0)->ev_hdlr.close)) \
+ 1)
struct vcd_clnt_state_table {
struct {
u32(*close) (struct vcd_clnt_ctxt *cctxt);
u32(*encode_start) (struct vcd_clnt_ctxt *cctxt);
u32(*encode_frame) (struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame);
u32(*decode_start) (struct vcd_clnt_ctxt *cctxt,
struct vcd_sequence_hdr *seq_hdr);
u32(*decode_frame) (struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *input_frame);
u32(*pause) (struct vcd_clnt_ctxt *cctxt);
u32(*resume) (struct vcd_clnt_ctxt *cctxt);
u32(*flush) (struct vcd_clnt_ctxt *cctxt,
u32 mode);
u32(*stop) (struct vcd_clnt_ctxt *cctxt);
u32(*set_property) (struct vcd_clnt_ctxt *cctxt,
struct vcd_property_hdr *prop_hdr,
void *prop);
u32(*get_property) (struct vcd_clnt_ctxt *cctxt,
struct vcd_property_hdr *prop_hdr,
void *prop);
u32(*set_buffer_requirements) (struct vcd_clnt_ctxt *
cctxt,
enum vcd_buffer_type buffer,
struct
vcd_buffer_requirement *
buffer_req);
u32(*get_buffer_requirements) (struct vcd_clnt_ctxt *
cctxt,
enum vcd_buffer_type buffer,
struct
vcd_buffer_requirement *
buffer_req);
u32(*set_buffer) (struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer_type, u8 *buffer,
u32 buf_size);
u32(*allocate_buffer) (struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer, u32 buf_size,
u8 **vir_buf_addr, u8 **phy_buf_addr);
u32(*free_buffer) (struct vcd_clnt_ctxt *cctxt,
enum vcd_buffer_type buffer_type, u8 *buffer);
u32(*fill_output_buffer) (
struct vcd_clnt_ctxt *cctxt,
struct vcd_frame_data *buffer);
void (*clnt_cb) (struct vcd_clnt_ctxt *cctxt,
u32 event, u32 status, void *payload,
size_t sz, u32 *ddl_handle,
void *const client_data);
} ev_hdlr;
void (*entry) (struct vcd_clnt_ctxt *cctxt,
s32 state_event);
void (*exit) (struct vcd_clnt_ctxt *cctxt,
s32 state_event);
};
struct vcd_clnt_state_ctxt {
const struct vcd_clnt_state_table *state_table;
enum vcd_clnt_state_enum state;
};
extern void vcd_do_client_state_transition
(struct vcd_clnt_ctxt *cctxt,
enum vcd_clnt_state_enum to_state, u32 ev_code);
extern const struct vcd_clnt_state_table *vcd_get_client_state_table(
enum vcd_clnt_state_enum state);
#endif
@@ -0,0 +1,229 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_CORE_H_
#define _VCD_CORE_H_
#include <linux/msm_ion.h>
#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
#include "vcd_util.h"
#include "vcd_client_sm.h"
#include "vcd_power_sm.h"
#define VCD_SIGNATURE 0x75017591U
#define VCD_MIN_PERF_LEVEL 37900
#define VCD_DRIVER_CLIENTS_MAX 6
#define VCD_MAX_CLIENT_TRANSACTIONS 32
#define VCD_MAX_BUFFER_ENTRIES 32
#define VCD_SEQ_HDR_PADDING_BYTES 256
#define VCD_DEC_NUM_INTERLACED_FIELDS 2
#define VCD_TIMESTAMP_RESOLUTION 1000000
#define VCD_DEC_INITIAL_FRAME_RATE 30
#define VCD_MAXPERF_FPS_THRESHOLD_X_1000 (59*1000)
#define VCD_FIRST_IP_RCVD 0x00000004
#define VCD_FIRST_OP_RCVD 0x00000008
#define VCD_EOS_PREV_VALID 0x00000010
#define VCD_EOS_WAIT_OP_BUF 0x00000020
#define VCD_CLEANING_UP 0x00000040
#define VCD_STOP_PENDING 0x00000080
#define VCD_CLOSE_PENDING 0x00000100
#define VCD_IN_RECONFIG 0x00000200
#define VCD_FIRST_IP_DONE 0x00000400
enum vcd_command {
VCD_CMD_NONE,
VCD_CMD_DEVICE_INIT,
VCD_CMD_DEVICE_TERM,
VCD_CMD_DEVICE_RESET,
VCD_CMD_CODEC_START,
VCD_CMD_CODEC_STOP,
VCD_CMD_CODE_FRAME,
VCD_CMD_OUTPUT_FLUSH,
VCD_CMD_CLIENT_CLOSE
};
enum vcd_core_type {
VCD_CORE_1080P,
VCD_CORE_720P
};
struct vcd_cmd_q_element {
enum vcd_command pending_cmd;
};
struct vcd_buffer_entry {
struct list_head sched_list;
struct list_head list;
u32 valid;
u8 *alloc;
u8 *virtual;
u8 *physical;
size_t sz;
u32 allocated;
u32 in_use;
struct vcd_frame_data frame;
};
struct vcd_buffer_pool {
struct vcd_buffer_entry *entries;
u32 count;
struct vcd_buffer_requirement buf_req;
u32 validated;
u32 allocated;
u32 in_use;
struct list_head queue;
u16 q_len;
};
struct vcd_transc {
u32 in_use;
enum vcd_command type;
struct vcd_clnt_ctxt *cctxt;
struct vcd_buffer_entry *ip_buf_entry;
s64 time_stamp;
u32 flags;
u32 ip_frm_tag;
enum vcd_frame frame;
struct vcd_buffer_entry *op_buf_entry;
u32 input_done;
u32 frame_done;
};
struct vcd_dev_ctxt {
u32 ddl_cmd_concurrency;
u32 ddl_frame_ch_depth;
u32 ddl_cmd_ch_depth;
u32 ddl_frame_ch_interim;
u32 ddl_cmd_ch_interim;
u32 ddl_frame_ch_free;
u32 ddl_cmd_ch_free;
struct list_head sched_clnt_list;
struct vcd_init_config config;
u32 driver_ids[VCD_DRIVER_CLIENTS_MAX];
u32 refs;
u8 *device_base_addr;
void *hw_timer_handle;
u32 hw_time_out;
struct vcd_clnt_ctxt *cctxt_list_head;
enum vcd_command pending_cmd;
u32 command_continue;
struct vcd_transc *trans_tbl;
u32 trans_tbl_size;
enum vcd_power_state pwr_state;
enum vcd_pwr_clk_state pwr_clk_state;
u32 active_clnts;
u32 max_perf_lvl;
u32 reqd_perf_lvl;
u32 curr_perf_lvl;
u32 set_perf_lvl_pending;
};
struct vcd_clnt_status {
u32 req_perf_lvl;
u32 frame_submitted;
u32 frame_delayed;
u32 cmd_submitted;
u32 int_field_cnt;
s64 first_ts;
s64 prev_ts;
u64 time_elapsed;
struct vcd_frame_data eos_trig_ip_frm;
struct ddl_frame_data_tag eos_prev_op_frm;
u32 eos_prev_op_frm_status;
u32 last_err;
u32 last_evt;
u32 mask;
};
struct vcd_sched_clnt_ctx {
struct list_head list;
u32 clnt_active;
void *clnt_data;
u32 tkns;
u32 round_perfrm;
u32 rounds;
struct list_head ip_frm_list;
};
struct vcd_clnt_ctxt {
u32 signature;
struct vcd_clnt_state_ctxt clnt_state;
s32 driver_id;
u32 live;
u32 decoding;
u32 bframe;
u32 num_slices;
struct vcd_property_frame_rate frm_rate;
u32 frm_p_units;
u32 reqd_perf_lvl;
u32 time_resoln;
u32 time_frame_delta;
struct vcd_buffer_pool in_buf_pool;
struct vcd_buffer_pool out_buf_pool;
void (*callback) (u32 event, u32 status, void *info, size_t sz,
void *handle, void *const client_data);
void *client_data;
struct vcd_sched_clnt_ctx *sched_clnt_hdl;
u32 ddl_hdl_valid;
u32 *ddl_handle;
struct vcd_dev_ctxt *dev_ctxt;
struct vcd_cmd_q_element cmd_q;
struct vcd_sequence_hdr seq_hdr;
u8 *seq_hdr_phy_addr;
struct vcd_clnt_status status;
struct ion_client *vcd_ion_client;
u32 vcd_enable_ion;
struct vcd_clnt_ctxt *next;
u32 meta_mode;
int perf_set_by_client;
int secure;
bool is_turbo_enabled;
};
#define VCD_BUFFERPOOL_INUSE_DECREMENT(val) \
do { \
if ((val) > 0) \
val--; \
else { \
VCD_MSG_ERROR("%s(): Inconsistent val given in " \
" VCD_BUFFERPOOL_INUSE_DECREMENT\n", __func__); \
} \
} while (0)
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,96 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_DEVICE_SM_H_
#define _VCD_DEVICE_SM_H_
#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
#include "vcd_core.h"
struct vcd_dev_state_table;
struct vcd_dev_state_ctxt;
struct vcd_drv_ctxt;
enum vcd_dev_state_enum {
VCD_DEVICE_STATE_NULL = 0,
VCD_DEVICE_STATE_NOT_INIT,
VCD_DEVICE_STATE_INITING,
VCD_DEVICE_STATE_READY,
VCD_DEVICE_STATE_INVALID,
VCD_DEVICE_STATE_MAX,
VCD_DEVICE_STATE_32BIT = 0x7FFFFFFF
};
struct vcd_dev_state_table {
struct {
u32(*init) (struct vcd_drv_ctxt *drv_ctxt,
struct vcd_init_config *config,
s32 *driver_handle);
u32(*term) (struct vcd_drv_ctxt *drv_ctxt,
s32 driver_handle);
u32(*open) (struct vcd_drv_ctxt *drv_ctxt,
s32 driver_handle, u32 decoding,
void (*callback) (u32 event, u32 status,
void *info, size_t sz, void *handle,
void *const client_data),
void *client_data);
u32(*close) (struct vcd_drv_ctxt *drv_ctxt,
struct vcd_clnt_ctxt *cctxt);
u32(*resume) (struct vcd_drv_ctxt *drv_ctxt,
struct vcd_clnt_ctxt *cctxt);
u32(*set_dev_pwr) (struct vcd_drv_ctxt *drv_ctxt,
enum vcd_power_state pwr_state);
void (*dev_cb) (struct vcd_drv_ctxt *drv_ctxt,
u32 event, u32 status, void *payload,
size_t sz, u32 *ddl_handle,
void *const client_data);
void (*timeout) (struct vcd_drv_ctxt *drv_ctxt,
void *user_data);
} ev_hdlr;
void (*entry) (struct vcd_drv_ctxt *drv_ctxt,
s32 state_event);
void (*exit) (struct vcd_drv_ctxt *drv_ctxt,
s32 state_event);
};
#define DEVICE_STATE_EVENT_NUMBER(ppf) \
((u32 *) (&(((struct vcd_dev_state_table*)0)->ev_hdlr.ppf)) - \
(u32 *) (&(((struct vcd_dev_state_table*)0)->ev_hdlr.init)) \
+ 1)
struct vcd_dev_state_ctxt {
const struct vcd_dev_state_table *state_table;
enum vcd_dev_state_enum state;
};
struct vcd_drv_ctxt {
struct vcd_dev_state_ctxt dev_state;
struct vcd_dev_ctxt dev_ctxt;
struct mutex dev_mutex;
};
extern struct vcd_drv_ctxt *vcd_get_drv_context(void);
void vcd_continue(void);
#endif
@@ -0,0 +1,398 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <media/msm/vidc_type.h>
#include "vcd_power_sm.h"
#include "vcd_core.h"
#include "vcd.h"
#include "vcd_res_tracker.h"
u32 vcd_power_event(
struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt, u32 event)
{
u32 rc = VCD_S_SUCCESS;
VCD_MSG_MED("Device power state = %d", dev_ctxt->pwr_clk_state);
VCD_MSG_MED("event = 0x%x", event);
switch (event) {
case VCD_EVT_PWR_DEV_INIT_BEGIN:
case VCD_EVT_PWR_DEV_INIT_END:
case VCD_EVT_PWR_DEV_INIT_FAIL:
case VCD_EVT_PWR_DEV_TERM_BEGIN:
case VCD_EVT_PWR_DEV_TERM_END:
case VCD_EVT_PWR_DEV_TERM_FAIL:
case VCD_EVT_PWR_DEV_SLEEP_BEGIN:
case VCD_EVT_PWR_DEV_SLEEP_END:
case VCD_EVT_PWR_DEV_SET_PERFLVL:
case VCD_EVT_PWR_DEV_HWTIMEOUT:
{
rc = vcd_device_power_event(dev_ctxt, event,
cctxt);
break;
}
case VCD_EVT_PWR_CLNT_CMD_BEGIN:
case VCD_EVT_PWR_CLNT_CMD_END:
case VCD_EVT_PWR_CLNT_CMD_FAIL:
case VCD_EVT_PWR_CLNT_PAUSE:
case VCD_EVT_PWR_CLNT_RESUME:
case VCD_EVT_PWR_CLNT_FIRST_FRAME:
case VCD_EVT_PWR_CLNT_LAST_FRAME:
case VCD_EVT_PWR_CLNT_ERRFATAL:
{
rc = vcd_client_power_event(dev_ctxt, cctxt, event);
break;
}
}
if (VCD_FAILED(rc))
VCD_MSG_ERROR("vcd_power_event: event 0x%x failed", event);
return rc;
}
u32 vcd_device_power_event(struct vcd_dev_ctxt *dev_ctxt, u32 event,
struct vcd_clnt_ctxt *cctxt)
{
u32 rc = VCD_ERR_FAIL;
u32 set_perf_lvl;
switch (event) {
case VCD_EVT_PWR_DEV_INIT_BEGIN:
{
if (dev_ctxt->pwr_clk_state ==
VCD_PWRCLK_STATE_OFF) {
if (res_trk_get_max_perf_level(&dev_ctxt->
max_perf_lvl)) {
if (res_trk_power_up()) {
dev_ctxt->pwr_clk_state =
VCD_PWRCLK_STATE_ON_NOTCLOCKED;
dev_ctxt->curr_perf_lvl = 0;
dev_ctxt->reqd_perf_lvl = 0;
dev_ctxt->active_clnts = 0;
dev_ctxt->
set_perf_lvl_pending = false;
rc = vcd_enable_clock(dev_ctxt,
cctxt);
if (VCD_FAILED(rc)) {
(void)res_trk_power_down();
dev_ctxt->pwr_clk_state =
VCD_PWRCLK_STATE_OFF;
}
}
}
}
break;
}
case VCD_EVT_PWR_DEV_INIT_END:
case VCD_EVT_PWR_DEV_TERM_FAIL:
case VCD_EVT_PWR_DEV_SLEEP_BEGIN:
case VCD_EVT_PWR_DEV_HWTIMEOUT:
{
rc = vcd_gate_clock(dev_ctxt);
break;
}
case VCD_EVT_PWR_DEV_INIT_FAIL:
case VCD_EVT_PWR_DEV_TERM_END:
{
if (dev_ctxt->pwr_clk_state !=
VCD_PWRCLK_STATE_OFF) {
(void)vcd_disable_clock(dev_ctxt);
(void)res_trk_power_down();
dev_ctxt->pwr_clk_state =
VCD_PWRCLK_STATE_OFF;
dev_ctxt->curr_perf_lvl = 0;
dev_ctxt->reqd_perf_lvl = 0;
dev_ctxt->active_clnts = 0;
dev_ctxt->set_perf_lvl_pending = false;
rc = VCD_S_SUCCESS;
}
break;
}
case VCD_EVT_PWR_DEV_TERM_BEGIN:
case VCD_EVT_PWR_DEV_SLEEP_END:
{
rc = vcd_un_gate_clock(dev_ctxt);
break;
}
case VCD_EVT_PWR_DEV_SET_PERFLVL:
{
set_perf_lvl =
dev_ctxt->reqd_perf_lvl >
0 ? dev_ctxt->
reqd_perf_lvl : VCD_MIN_PERF_LEVEL;
rc = vcd_set_perf_level(dev_ctxt, set_perf_lvl);
break;
}
}
return rc;
}
u32 vcd_client_power_event(
struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt, u32 event)
{
u32 rc = VCD_ERR_FAIL;
switch (event) {
case VCD_EVT_PWR_CLNT_CMD_BEGIN:
{
rc = vcd_un_gate_clock(dev_ctxt);
break;
}
case VCD_EVT_PWR_CLNT_CMD_END:
{
rc = vcd_gate_clock(dev_ctxt);
break;
}
case VCD_EVT_PWR_CLNT_CMD_FAIL:
{
if (!vcd_core_is_busy(dev_ctxt))
rc = vcd_gate_clock(dev_ctxt);
break;
}
case VCD_EVT_PWR_CLNT_PAUSE:
case VCD_EVT_PWR_CLNT_LAST_FRAME:
case VCD_EVT_PWR_CLNT_ERRFATAL:
{
if (cctxt) {
rc = VCD_S_SUCCESS;
if (cctxt->status.req_perf_lvl) {
dev_ctxt->reqd_perf_lvl -=
cctxt->reqd_perf_lvl;
cctxt->status.req_perf_lvl = false;
rc = vcd_set_perf_level(dev_ctxt,
dev_ctxt->reqd_perf_lvl);
}
}
break;
}
case VCD_EVT_PWR_CLNT_RESUME:
case VCD_EVT_PWR_CLNT_FIRST_FRAME:
{
if (cctxt) {
rc = VCD_S_SUCCESS;
if (!cctxt->status.req_perf_lvl) {
dev_ctxt->reqd_perf_lvl +=
cctxt->reqd_perf_lvl;
cctxt->status.req_perf_lvl = true;
rc = vcd_set_perf_level(dev_ctxt,
dev_ctxt->reqd_perf_lvl);
}
}
break;
}
}
return rc;
}
u32 vcd_enable_clock(struct vcd_dev_ctxt *dev_ctxt,
struct vcd_clnt_ctxt *cctxt)
{
u32 rc = VCD_S_SUCCESS;
u32 set_perf_lvl;
if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF) {
VCD_MSG_ERROR("vcd_enable_clock(): Already in state "
"VCD_PWRCLK_STATE_OFF\n");
rc = VCD_ERR_FAIL;
} else if (dev_ctxt->pwr_clk_state ==
VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
set_perf_lvl =
dev_ctxt->reqd_perf_lvl >
0 ? dev_ctxt->
reqd_perf_lvl : VCD_MIN_PERF_LEVEL;
rc = vcd_set_perf_level(dev_ctxt, set_perf_lvl);
if (!VCD_FAILED(rc)) {
if (res_trk_enable_clocks()) {
dev_ctxt->pwr_clk_state =
VCD_PWRCLK_STATE_ON_CLOCKED;
}
} else {
rc = VCD_ERR_FAIL;
}
}
if (!VCD_FAILED(rc))
dev_ctxt->active_clnts++;
return rc;
}
u32 vcd_disable_clock(struct vcd_dev_ctxt *dev_ctxt)
{
u32 rc = VCD_S_SUCCESS;
if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF) {
VCD_MSG_ERROR("vcd_disable_clock(): Already in state "
"VCD_PWRCLK_STATE_OFF\n");
rc = VCD_ERR_FAIL;
} else if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKED ||
dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKGATED) {
dev_ctxt->active_clnts--;
if (!dev_ctxt->active_clnts) {
if (!res_trk_disable_clocks())
rc = VCD_ERR_FAIL;
dev_ctxt->pwr_clk_state =
VCD_PWRCLK_STATE_ON_NOTCLOCKED;
dev_ctxt->curr_perf_lvl = 0;
}
}
return rc;
}
u32 vcd_set_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl)
{
u32 rc = VCD_S_SUCCESS;
if (!vcd_core_is_busy(dev_ctxt)) {
if (res_trk_set_perf_level(perf_lvl,
&dev_ctxt->curr_perf_lvl, dev_ctxt)) {
dev_ctxt->set_perf_lvl_pending = false;
} else {
rc = VCD_ERR_FAIL;
dev_ctxt->set_perf_lvl_pending = true;
}
} else {
dev_ctxt->set_perf_lvl_pending = true;
}
return rc;
}
u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt)
{
u32 rc = VCD_S_SUCCESS;
#ifdef CONFIG_MSM_BUS_SCALING
struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
pr_err("\n Setting Turbo mode !!");
if (res_trk_update_bus_perf_level(dev_ctxt,
RESTRK_1080P_TURBO_PERF_LEVEL) < 0) {
pr_err("\n %s(): update buf perf level failed\n",
__func__);
return false;
}
dev_ctxt->curr_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
vcd_update_decoder_perf_level(dev_ctxt, RESTRK_1080P_TURBO_PERF_LEVEL);
#endif
return rc;
}
u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl)
{
u32 rc = VCD_S_SUCCESS;
if (res_trk_set_perf_level(perf_lvl,
&dev_ctxt->curr_perf_lvl, dev_ctxt)) {
dev_ctxt->set_perf_lvl_pending = false;
} else {
rc = VCD_ERR_FAIL;
dev_ctxt->set_perf_lvl_pending = true;
}
return rc;
}
u32 vcd_update_clnt_perf_lvl(
struct vcd_clnt_ctxt *cctxt,
struct vcd_property_frame_rate *fps, u32 frm_p_units)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
u32 new_perf_lvl;
new_perf_lvl = frm_p_units *\
(fps->fps_numerator / fps->fps_denominator);
if ((fps->fps_numerator * 1000) / fps->fps_denominator
> VCD_MAXPERF_FPS_THRESHOLD_X_1000) {
u32 max_perf_level = 0;
if (res_trk_get_max_perf_level(&max_perf_level)) {
new_perf_lvl = max_perf_level;
VCD_MSG_HIGH("Using max perf level(%d) for >60fps\n",
new_perf_lvl);
} else {
VCD_MSG_ERROR("Failed to get max perf level\n");
}
}
if (cctxt->status.req_perf_lvl) {
dev_ctxt->reqd_perf_lvl =
dev_ctxt->reqd_perf_lvl - cctxt->reqd_perf_lvl +
new_perf_lvl;
rc = vcd_set_perf_level(cctxt->dev_ctxt,
dev_ctxt->reqd_perf_lvl);
}
cctxt->reqd_perf_lvl = new_perf_lvl;
return rc;
}
u32 vcd_gate_clock(struct vcd_dev_ctxt *dev_ctxt)
{
u32 rc = VCD_S_SUCCESS;
if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF ||
dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
VCD_MSG_ERROR("%s(): Clk is Off or Not Clked yet\n", __func__);
rc = VCD_ERR_FAIL;
} else if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKGATED)
rc = VCD_S_SUCCESS;
else if (res_trk_disable_clocks())
dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_ON_CLOCKGATED;
else
rc = VCD_ERR_FAIL;
return rc;
}
u32 vcd_un_gate_clock(struct vcd_dev_ctxt *dev_ctxt)
{
u32 rc = VCD_S_SUCCESS;
if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_OFF ||
dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_NOTCLOCKED) {
VCD_MSG_ERROR("%s(): Clk is Off or Not Clked yet\n", __func__);
rc = VCD_ERR_FAIL;
} else if (dev_ctxt->pwr_clk_state == VCD_PWRCLK_STATE_ON_CLOCKED)
rc = VCD_S_SUCCESS;
else if (res_trk_enable_clocks())
dev_ctxt->pwr_clk_state = VCD_PWRCLK_STATE_ON_CLOCKED;
else
rc = VCD_ERR_FAIL;
return rc;
}
@@ -0,0 +1,43 @@
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_POWERSM_H_
#define _VCD_POWERSM_H_
#define VCD_EVT_PWR_BASE 0x5000
#define VCD_EVT_PWR_DEV_INIT_BEGIN (VCD_EVT_PWR_BASE + 0x1)
#define VCD_EVT_PWR_DEV_INIT_END (VCD_EVT_PWR_BASE + 0x2)
#define VCD_EVT_PWR_DEV_INIT_FAIL (VCD_EVT_PWR_BASE + 0x3)
#define VCD_EVT_PWR_DEV_TERM_BEGIN (VCD_EVT_PWR_BASE + 0x4)
#define VCD_EVT_PWR_DEV_TERM_END (VCD_EVT_PWR_BASE + 0x5)
#define VCD_EVT_PWR_DEV_TERM_FAIL (VCD_EVT_PWR_BASE + 0x6)
#define VCD_EVT_PWR_DEV_SLEEP_BEGIN (VCD_EVT_PWR_BASE + 0x7)
#define VCD_EVT_PWR_DEV_SLEEP_END (VCD_EVT_PWR_BASE + 0x8)
#define VCD_EVT_PWR_DEV_SET_PERFLVL (VCD_EVT_PWR_BASE + 0x9)
#define VCD_EVT_PWR_DEV_HWTIMEOUT (VCD_EVT_PWR_BASE + 0xa)
#define VCD_EVT_PWR_CLNT_CMD_BEGIN (VCD_EVT_PWR_BASE + 0xb)
#define VCD_EVT_PWR_CLNT_CMD_END (VCD_EVT_PWR_BASE + 0xc)
#define VCD_EVT_PWR_CLNT_CMD_FAIL (VCD_EVT_PWR_BASE + 0xd)
#define VCD_EVT_PWR_CLNT_PAUSE (VCD_EVT_PWR_BASE + 0xe)
#define VCD_EVT_PWR_CLNT_RESUME (VCD_EVT_PWR_BASE + 0xf)
#define VCD_EVT_PWR_CLNT_FIRST_FRAME (VCD_EVT_PWR_BASE + 0x10)
#define VCD_EVT_PWR_CLNT_LAST_FRAME (VCD_EVT_PWR_BASE + 0x11)
#define VCD_EVT_PWR_CLNT_ERRFATAL (VCD_EVT_PWR_BASE + 0x12)
enum vcd_pwr_clk_state {
VCD_PWRCLK_STATE_OFF = 0,
VCD_PWRCLK_STATE_ON_NOTCLOCKED,
VCD_PWRCLK_STATE_ON_CLOCKED,
VCD_PWRCLK_STATE_ON_CLOCKGATED
};
#endif
@@ -0,0 +1,296 @@
/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <media/msm/vidc_type.h>
#include "vcd.h"
#define NORMALIZATION_FACTOR 3600
#define ADJUST_CLIENT_ROUNDS(client, round_adjustment) \
do {\
if ((client)->rounds < round_adjustment) {\
(client)->rounds = 0;\
VCD_MSG_HIGH("%s(): WARNING: Scheduler list unsorted",\
__func__);\
} else\
(client)->rounds -= round_adjustment;\
} while (0)
u32 vcd_sched_create(struct list_head *sched_list)
{
u32 rc = VCD_S_SUCCESS;
if (!sched_list) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else
INIT_LIST_HEAD(sched_list);
return rc;
}
void vcd_sched_destroy(struct list_head *sched_clnt_list)
{
struct vcd_sched_clnt_ctx *sched_clnt, *sched_clnt_next;
if (sched_clnt_list)
list_for_each_entry_safe(sched_clnt,
sched_clnt_next, sched_clnt_list, list) {
list_del_init(&sched_clnt->list);
sched_clnt->clnt_active = false;
}
}
void insert_client_in_list(struct list_head *sched_clnt_list,
struct vcd_sched_clnt_ctx *sched_new_clnt, bool tail)
{
struct vcd_sched_clnt_ctx *sched_clnt;
if (!list_empty(sched_clnt_list)) {
if (tail)
sched_clnt = list_entry(sched_clnt_list->prev,
struct vcd_sched_clnt_ctx, list);
else
sched_clnt = list_first_entry(sched_clnt_list,
struct vcd_sched_clnt_ctx, list);
sched_new_clnt->rounds = sched_clnt->rounds;
} else
sched_new_clnt->rounds = 0;
if (tail)
list_add_tail(&sched_new_clnt->list, sched_clnt_list);
else
list_add(&sched_new_clnt->list, sched_clnt_list);
}
u32 vcd_sched_add_client(struct vcd_clnt_ctxt *cctxt)
{
struct vcd_property_hdr prop_hdr;
struct vcd_sched_clnt_ctx *sched_cctxt;
u32 rc = VCD_S_SUCCESS;
if (!cctxt) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else if (cctxt->sched_clnt_hdl)
VCD_MSG_HIGH(
"%s(): Scheduler client already exists!", __func__);
else {
sched_cctxt = (struct vcd_sched_clnt_ctx *)
kmalloc(sizeof(struct vcd_sched_clnt_ctx),
GFP_KERNEL);
if (sched_cctxt) {
prop_hdr.prop_id = DDL_I_FRAME_PROC_UNITS;
prop_hdr.sz = sizeof(cctxt->frm_p_units);
rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
&cctxt->frm_p_units);
if (VCD_FAILED(rc)) {
kfree(sched_cctxt);
VCD_MSG_ERROR(
"Failed: Get DDL_I_FRAME_PROC_UNITS");
return rc;
}
if (cctxt->decoding) {
cctxt->frm_rate.fps_numerator =
VCD_DEC_INITIAL_FRAME_RATE;
cctxt->frm_rate.fps_denominator = 1;
} else {
prop_hdr.prop_id = VCD_I_FRAME_RATE;
prop_hdr.sz = sizeof(cctxt->frm_rate);
rc = ddl_get_property(cctxt->ddl_handle,
&prop_hdr, &cctxt->frm_rate);
if (VCD_FAILED(rc)) {
kfree(sched_cctxt);
VCD_MSG_ERROR(
"Failed: Get VCD_I_FRAME_RATE");
return rc;
}
}
if (!cctxt->perf_set_by_client)
cctxt->reqd_perf_lvl = cctxt->frm_p_units *
cctxt->frm_rate.fps_numerator /
cctxt->frm_rate.fps_denominator;
cctxt->sched_clnt_hdl = sched_cctxt;
memset(sched_cctxt, 0,
sizeof(struct vcd_sched_clnt_ctx));
sched_cctxt->tkns = 0;
sched_cctxt->round_perfrm = NORMALIZATION_FACTOR *
cctxt->frm_rate.fps_denominator /
cctxt->frm_rate.fps_numerator;
sched_cctxt->clnt_active = true;
sched_cctxt->clnt_data = cctxt;
INIT_LIST_HEAD(&sched_cctxt->ip_frm_list);
insert_client_in_list(
&cctxt->dev_ctxt->sched_clnt_list,
sched_cctxt, false);
}
}
return rc;
}
u32 vcd_sched_remove_client(struct vcd_sched_clnt_ctx *sched_cctxt)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_clnt_ctxt *cctxt;
if (!sched_cctxt) {
VCD_MSG_ERROR("%s(): Invalid handle ptr", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else if (!list_empty(&sched_cctxt->ip_frm_list)) {
VCD_MSG_ERROR(
"%s(): Cannot remove client, queue no empty", __func__);
rc = VCD_ERR_ILLEGAL_OP;
} else {
cctxt = sched_cctxt->clnt_data;
list_del(&sched_cctxt->list);
memset(sched_cctxt, 0,
sizeof(struct vcd_sched_clnt_ctx));
kfree(sched_cctxt);
}
return rc;
}
u32 vcd_sched_update_config(struct vcd_clnt_ctxt *cctxt)
{
u32 rc = VCD_S_SUCCESS;
if (!cctxt || !cctxt->sched_clnt_hdl) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else {
cctxt->sched_clnt_hdl->rounds /=
cctxt->sched_clnt_hdl->round_perfrm;
cctxt->sched_clnt_hdl->round_perfrm =
NORMALIZATION_FACTOR *
cctxt->frm_rate.fps_denominator /
cctxt->frm_rate.fps_numerator;
cctxt->sched_clnt_hdl->rounds *=
cctxt->sched_clnt_hdl->round_perfrm;
}
return rc;
}
u32 vcd_sched_queue_buffer(
struct vcd_sched_clnt_ctx *sched_cctxt,
struct vcd_buffer_entry *buffer, u32 tail)
{
u32 rc = VCD_S_SUCCESS;
if (!sched_cctxt || !buffer) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else if (tail)
list_add_tail(&buffer->sched_list,
&sched_cctxt->ip_frm_list);
else
list_add(&buffer->sched_list, &sched_cctxt->ip_frm_list);
return rc;
}
u32 vcd_sched_dequeue_buffer(
struct vcd_sched_clnt_ctx *sched_cctxt,
struct vcd_buffer_entry **buffer)
{
u32 rc = VCD_ERR_QEMPTY;
if (!sched_cctxt || !buffer) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else {
*buffer = NULL;
if (!list_empty(&sched_cctxt->ip_frm_list)) {
*buffer = list_first_entry(
&sched_cctxt->ip_frm_list,
struct vcd_buffer_entry,
sched_list);
list_del(&(*buffer)->sched_list);
rc = VCD_S_SUCCESS;
}
}
return rc;
}
u32 vcd_sched_mark_client_eof(struct vcd_sched_clnt_ctx *sched_cctxt)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_buffer_entry *buffer = NULL;
if (!sched_cctxt) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else if (!list_empty(&sched_cctxt->ip_frm_list)) {
buffer = list_entry(sched_cctxt->ip_frm_list.prev,
struct vcd_buffer_entry, sched_list);
buffer->frame.flags |= VCD_FRAME_FLAG_EOS;
} else
rc = VCD_ERR_QEMPTY;
return rc;
}
u32 vcd_sched_suspend_resume_clnt(
struct vcd_clnt_ctxt *cctxt, u32 state)
{
u32 rc = VCD_S_SUCCESS;
struct vcd_sched_clnt_ctx *sched_cctxt;
if (!cctxt || !cctxt->sched_clnt_hdl) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else {
sched_cctxt = cctxt->sched_clnt_hdl;
if (state != sched_cctxt->clnt_active) {
sched_cctxt->clnt_active = state;
if (state)
insert_client_in_list(&cctxt->dev_ctxt->\
sched_clnt_list, sched_cctxt, false);
else
list_del_init(&sched_cctxt->list);
}
}
return rc;
}
u32 vcd_sched_get_client_frame(struct list_head *sched_clnt_list,
struct vcd_clnt_ctxt **cctxt,
struct vcd_buffer_entry **buffer)
{
u32 rc = VCD_ERR_QEMPTY, round_adjustment = 0;
struct vcd_sched_clnt_ctx *sched_clnt, *clnt_nxt;
if (!sched_clnt_list || !cctxt || !buffer) {
VCD_MSG_ERROR("%s(): Invalid parameter", __func__);
rc = VCD_ERR_ILLEGAL_PARM;
} else if (!list_empty(sched_clnt_list)) {
*cctxt = NULL;
*buffer = NULL;
list_for_each_entry_safe(sched_clnt,
clnt_nxt, sched_clnt_list, list) {
if (&sched_clnt->list == sched_clnt_list->next)
round_adjustment = sched_clnt->rounds;
if (*cctxt) {
if ((*cctxt)->sched_clnt_hdl->rounds >=
sched_clnt->rounds)
list_move(&(*cctxt)->sched_clnt_hdl\
->list, &sched_clnt->list);
ADJUST_CLIENT_ROUNDS(sched_clnt,
round_adjustment);
} else if (sched_clnt->tkns &&
!list_empty(&sched_clnt->ip_frm_list)) {
*cctxt = sched_clnt->clnt_data;
sched_clnt->rounds += sched_clnt->round_perfrm;
} else
ADJUST_CLIENT_ROUNDS(sched_clnt,
round_adjustment);
}
if (*cctxt) {
rc = vcd_sched_dequeue_buffer(
(*cctxt)->sched_clnt_hdl, buffer);
if (rc == VCD_S_SUCCESS) {
(*cctxt)->sched_clnt_hdl->tkns--;
ADJUST_CLIENT_ROUNDS((*cctxt)->\
sched_clnt_hdl, round_adjustment);
}
}
}
return rc;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,106 @@
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "vidc_type.h"
#include "vcd_util.h"
u32 vcd_critical_section_create(u32 **p_cs)
{
struct mutex *lock;
if (!p_cs) {
VCD_MSG_ERROR("Bad critical section ptr");
return VCD_ERR_BAD_POINTER;
} else {
lock = kmalloc(sizeof(struct mutex), GFP_KERNEL);
if (!lock) {
VCD_MSG_ERROR("Failed: vcd_critical_section_create");
return VCD_ERR_ALLOC_FAIL;
}
mutex_init(lock);
*p_cs = (u32 *) lock;
return VCD_S_SUCCESS;
}
}
u32 vcd_critical_section_release(u32 *cs)
{
struct mutex *lock = (struct mutex *)cs;
if (!lock) {
VCD_MSG_ERROR("Bad critical section object");
return VCD_ERR_BAD_POINTER;
}
mutex_destroy(lock);
kfree(cs);
return VCD_S_SUCCESS;
}
u32 vcd_critical_section_enter(u32 *cs)
{
struct mutex *lock = (struct mutex *)cs;
if (!lock) {
VCD_MSG_ERROR("Bad critical section object");
return VCD_ERR_BAD_POINTER;
} else
mutex_lock(lock);
return VCD_S_SUCCESS;
}
u32 vcd_critical_section_leave(u32 *cs)
{
struct mutex *lock = (struct mutex *)cs;
if (!lock) {
VCD_MSG_ERROR("Bad critical section object");
return VCD_ERR_BAD_POINTER;
} else
mutex_unlock(lock);
return VCD_S_SUCCESS;
}
int vcd_pmem_alloc(u32 size, u8 **kernel_vaddr, u8 **phy_addr)
{
*phy_addr =
(u8 *) pmem_kalloc(size, PMEM_MEMTYPE | PMEM_ALIGNMENT_4K);
if (!IS_ERR((void *)*phy_addr)) {
*kernel_vaddr = ioremap((unsigned long)*phy_addr, size);
if (!*kernel_vaddr) {
pr_err("%s: could not ioremap in kernel pmem buffers\n",
__func__);
pmem_kfree((s32) *phy_addr);
return -ENOMEM;
}
pr_debug("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
(u32) *phy_addr, (u32) *kernel_vaddr);
return 0;
} else {
pr_err("%s: could not allocte in kernel pmem buffers\n",
__func__);
return -ENOMEM;
}
}
int vcd_pmem_free(u8 *kernel_vaddr, u8 *phy_addr)
{
iounmap((void *)kernel_vaddr);
pmem_kfree((s32) phy_addr);
return 0;
}
@@ -0,0 +1,52 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _VCD_UTIL_H_
#define _VCD_UTIL_H_
#include <media/msm/vidc_type.h>
#include <media/msm/vcd_api.h>
#if DEBUG
#define VCD_MSG_LOW(xx_fmt...) printk(KERN_INFO "\n\t* " xx_fmt)
#define VCD_MSG_MED(xx_fmt...) printk(KERN_INFO "\n * " xx_fmt)
#define VCD_MSG_HIGH(xx_fmt...) printk(KERN_WARNING "\n" xx_fmt)
#define VCD_MSG_ERROR(xx_fmt...) printk(KERN_ERR "\n err: " xx_fmt)
#else
#define VCD_MSG_LOW(xx_fmt...)
#define VCD_MSG_MED(xx_fmt...)
#define VCD_MSG_HIGH(xx_fmt...)
#define VCD_MSG_ERROR(xx_fmt...)
#endif
#define VCD_MSG_FATAL(xx_fmt...) printk(KERN_ERR "\n<FATAL> " xx_fmt)
#define VCD_FAILED_RETURN(rc, xx_fmt...) \
do { \
if (VCD_FAILED(rc)) { \
printk(KERN_ERR xx_fmt); \
return rc; \
} \
} while (0)
#define VCD_FAILED_DEVICE_FATAL(rc) \
(rc == VCD_ERR_HW_FATAL ? true : false)
#define VCD_FAILED_CLIENT_FATAL(rc) \
(rc == VCD_ERR_CLIENT_FATAL ? true : false)
#define VCD_FAILED_FATAL(rc) \
((VCD_FAILED_DEVICE_FATAL(rc) || VCD_FAILED_CLIENT_FATAL(rc)) \
? true : false)
#endif