1766 lines
53 KiB
C
1766 lines
53 KiB
C
/*
|
|
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Description:
|
|
*/
|
|
#include <linux/mm.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/list.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/version.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/io.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/dma-buf.h>
|
|
|
|
#include <linux/reset.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/poll.h>
|
|
|
|
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
|
|
|
#include "tahoe.h"
|
|
#include "tahoe_register.h"
|
|
|
|
#define IRQ_FRM_DONE_FBC 0x1
|
|
#define IRQ_FRM_START 0x2
|
|
#define IRQ_SCR_WRITE 0x4
|
|
#define IRQ_RDMA_DONE 0x8
|
|
#define IRQ_PRELOAD_DONE 0x10
|
|
#define IRQ_ROWRC_1 0x20
|
|
#define IRQ_ROWRC_2 0x40
|
|
#define IRQ_FRM_DONE_EC 0x80
|
|
#define IRQ_FRM_DONE_LPF 0x100
|
|
#define IRQ_FRM_DONE_RDO 0x200
|
|
#define IRQ_FRM_DONE_ME 0x400
|
|
#define IRQ_SLICE_DONE_FBC 0x800
|
|
#define IRQ_SLICE_DONE_EC 0x1000
|
|
#define IRQ_SLICE_DONE_LPF 0x2000
|
|
#define IRQ_SLICE_DONE_RDO 0x4000
|
|
#define IRQ_SLICE_DONE_ME 0x8000
|
|
#define IRQ_ES_OVERFLOW 0x10000
|
|
#define IRQ_RESERVED 0x20000
|
|
#define IRQ_LOW_LATENCY 0x40000
|
|
|
|
#define DRIVER_NAME "tahoe"
|
|
#define DEVICE_NAME "tahoe"
|
|
#define CLASS_NAME "tahoe"
|
|
|
|
#define LOG_ALL 0
|
|
#define LOG_INFO 1
|
|
#define LOG_DEBUG 2
|
|
#define LOG_ERROR 3
|
|
|
|
MODULE_IMPORT_NS(DMA_BUF);
|
|
|
|
static s32 print_level = LOG_ERROR;
|
|
#define enc_pr(level, x...) \
|
|
do { \
|
|
if (level >= print_level) \
|
|
printk(x); \
|
|
} while (0)
|
|
|
|
static s32 clock_gate_count = 0;
|
|
|
|
static struct venc_drv_buffer_t fw_buffer; //fw addr
|
|
#define MC_SIZE (4096 * 1024)
|
|
#define MAX_INSTANCE 4
|
|
|
|
static int s_interrupt_flag;
|
|
static wait_queue_head_t s_interrupt_wait_q;
|
|
|
|
static struct venc_drv_context_t s_tahoe_drv_context;
|
|
static s32 s_tahoe_major;
|
|
static s32 s_register_flag;
|
|
static struct device *tahoe_dev;
|
|
static struct platform_device *tahoe_pdev;
|
|
|
|
static s32 s_tahoe_open_ref_count;
|
|
static int s_tahoe_irq;
|
|
static bool s_tahoe_irq_requested;
|
|
|
|
static spinlock_t s_vpu_lock = __SPIN_LOCK_UNLOCKED(s_vpu_lock);
|
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(6, 3, 13)
|
|
static DEFINE_SEMAPHORE(s_vpu_sem);
|
|
#else
|
|
static DEFINE_SEMAPHORE(s_vpu_sem, 1);
|
|
#endif
|
|
static struct list_head s_vbp_head = LIST_HEAD_INIT(s_vbp_head);
|
|
|
|
static struct venc_drv_common_buffer_t s_video_memory[MAX_INSTANCE] = {0}; //每个通道单独申请36M,传到固件中;
|
|
static struct venc_drv_buffer_t s_tahoe_register = {0};
|
|
static bool use_reserve;
|
|
static u32 cma_cfg_size;
|
|
|
|
static struct tasklet_struct tahoe_tasklet;
|
|
static struct venc_bit_firmware_info_t s_bit_firmware_info;
|
|
|
|
static spinlock_t s_dma_buf_lock = __SPIN_LOCK_UNLOCKED(s_dma_buf_lock);
|
|
static struct list_head s_dma_bufp_head = LIST_HEAD_INIT(s_dma_bufp_head);
|
|
|
|
static u32 clock_a;
|
|
|
|
struct tahoe_clks {
|
|
struct clk *sys_tahoe;
|
|
struct clk *tahoe_clk;
|
|
};
|
|
|
|
static struct tahoe_clks s_tahoe_clks;
|
|
|
|
struct tahoe_rsts {
|
|
struct reset_control *core_rst;
|
|
struct reset_control *a_rst;
|
|
struct reset_control *apb_rst;
|
|
struct reset_control *sys_rst;
|
|
};
|
|
|
|
static struct tahoe_rsts s_tahoe_rsts;
|
|
|
|
static void tahoe_clk_enable(struct tahoe_clks *clks);
|
|
static void tahoe_clk_disable(struct tahoe_clks *clks);
|
|
static s32 tahoe_free_buffers(struct file *filp);
|
|
|
|
static void dma_flush(u32 buf_start, u32 buf_size)
|
|
{
|
|
if (tahoe_pdev)
|
|
dma_sync_single_for_device(
|
|
&tahoe_pdev->dev, buf_start,
|
|
buf_size, DMA_TO_DEVICE);
|
|
}
|
|
|
|
static void cache_flush(u32 buf_start, u32 buf_size)
|
|
{
|
|
if (tahoe_pdev)
|
|
dma_sync_single_for_cpu(
|
|
&tahoe_pdev->dev, buf_start,
|
|
buf_size, DMA_FROM_DEVICE);
|
|
}
|
|
|
|
//__need_modify__
|
|
static void tahoe_isr_tasklet(ulong data)
|
|
{
|
|
#if 0
|
|
u32 intr_reason;
|
|
struct venc_drv_context_t *dev = (struct venc_drv_context_t *)data;
|
|
|
|
/* notify the interrupt to user space */
|
|
if (dev->async_queue) {
|
|
enc_pr(LOG_ALL, "kill_fasync e %s\n", __func__);
|
|
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
|
|
}
|
|
|
|
intr_reason = dev->interrupt_flag;
|
|
if (intr_reason) {
|
|
dev->interrupt_flag = 0;
|
|
enc_pr(LOG_INFO, "isr_tasklet intr:0x%08x\n", intr_reason);
|
|
s_interrupt_flag = 1;
|
|
wake_up_interruptible(&s_interrupt_wait_q);
|
|
}
|
|
#endif
|
|
struct venc_drv_context_t *s_context = (struct venc_drv_context_t *)data;
|
|
atomic_inc(&s_context->request_ready);
|
|
wake_up_interruptible(&s_context->request_complete);
|
|
|
|
enc_pr(LOG_ALL, "[-]%s\n", __func__);
|
|
}
|
|
|
|
//__need_modify__
|
|
static irqreturn_t tahoe_irq_handler(int irq, void *dev_id)
|
|
{
|
|
struct venc_drv_context_t *dev = (struct venc_drv_context_t *)dev_id;
|
|
|
|
dev->interrupt_reason = ReadTahoeRegister(TAHOE_VRISC_IRQ_STAT);
|
|
enc_pr(LOG_INFO, "interrupt_reason 0x%lx\n", dev->interrupt_reason);
|
|
WriteTahoeRegister(TAHOE_VRISC_IRQ_STAT, ~dev->interrupt_reason);
|
|
if (dev->interrupt_reason & IRQ_PRELOAD_DONE) {
|
|
//preload_irq_flag = 1;
|
|
enc_pr(LOG_INFO, "preload irq received, preload done\n");
|
|
}
|
|
|
|
if (dev->interrupt_reason & IRQ_SCR_WRITE) {
|
|
//scrw_irq_flag = 1;
|
|
enc_pr(LOG_INFO, "scr write irq received\n");
|
|
}
|
|
|
|
if (dev->interrupt_reason & IRQ_FRM_DONE_FBC) {
|
|
enc_pr(LOG_INFO, "frame done irq received\n");
|
|
tasklet_schedule(&tahoe_tasklet);
|
|
}
|
|
//tasklet_schedule(&tahoe_tasklet);
|
|
enc_pr(LOG_ALL, "[-]%s\n", __func__);
|
|
|
|
//wake_up_interruptible(&s_interrupt_wait_q);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int tahoe_dma_buffer_map(struct tahoe_dma_cfg *cfg)
|
|
{
|
|
int ret = -1;
|
|
int fd = -1;
|
|
struct page *page = NULL;
|
|
struct dma_buf *dbuf = NULL;
|
|
struct dma_buf_attachment *d_att = NULL;
|
|
struct sg_table *sg = NULL;
|
|
void *vaddr = NULL;
|
|
struct device *dev = NULL;
|
|
enum dma_data_direction dir;
|
|
|
|
if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) {
|
|
enc_pr(LOG_ERROR, "error dma param\n");
|
|
return -EINVAL;
|
|
}
|
|
fd = cfg->fd;
|
|
dev = cfg->dev;
|
|
dir = cfg->dir;
|
|
|
|
dbuf = dma_buf_get(fd);
|
|
if (IS_ERR_OR_NULL(dbuf)) {
|
|
enc_pr(LOG_ERROR, "failed to get dma buffer,fd %d\n",fd);
|
|
return -EINVAL;
|
|
}
|
|
|
|
d_att = dma_buf_attach(dbuf, dev);
|
|
if (IS_ERR(d_att)) {
|
|
enc_pr(LOG_ERROR, "failed to set dma attach\n");
|
|
goto attach_err;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
|
|
sg = dma_buf_map_attachment(d_att, dir);
|
|
#else
|
|
sg = dma_buf_map_attachment_unlocked(d_att, dir);
|
|
#endif
|
|
if (IS_ERR(sg)) {
|
|
enc_pr(LOG_ERROR, "failed to get dma sg\n");
|
|
goto map_attach_err;
|
|
}
|
|
|
|
page = sg_page(sg->sgl);
|
|
cfg->paddr = PFN_PHYS(page_to_pfn(page));
|
|
cfg->dbuf = dbuf;
|
|
cfg->attach = d_att;
|
|
cfg->vaddr = vaddr;
|
|
cfg->sg = sg;
|
|
|
|
return 0;
|
|
|
|
map_attach_err:
|
|
dma_buf_detach(dbuf, d_att);
|
|
attach_err:
|
|
dma_buf_put(dbuf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void tahoe_dma_buffer_unmap(struct tahoe_dma_cfg *cfg)
|
|
{
|
|
int fd = -1;
|
|
struct dma_buf *dbuf = NULL;
|
|
struct dma_buf_attachment *d_att = NULL;
|
|
struct sg_table *sg = NULL;
|
|
/*void *vaddr = NULL;*/
|
|
struct device *dev = NULL;
|
|
enum dma_data_direction dir;
|
|
|
|
if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL
|
|
|| cfg->dbuf == NULL /*|| cfg->vaddr == NULL*/
|
|
|| cfg->attach == NULL || cfg->sg == NULL) {
|
|
enc_pr(LOG_ERROR, "unmap: Error dma param\n");
|
|
return;
|
|
}
|
|
|
|
fd = cfg->fd;
|
|
dev = cfg->dev;
|
|
dir = cfg->dir;
|
|
dbuf = cfg->dbuf;
|
|
d_att = cfg->attach;
|
|
sg = cfg->sg;
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
|
|
dma_buf_unmap_attachment(d_att, sg, dir);
|
|
#else
|
|
dma_buf_unmap_attachment_unlocked(d_att, sg, dir);
|
|
#endif
|
|
dma_buf_detach(dbuf, d_att);
|
|
dma_buf_put(dbuf);
|
|
|
|
enc_pr(LOG_INFO, "vpu_dma_buffer_unmap fd %d\n",fd);
|
|
}
|
|
|
|
static s32 tahoe_dma_buffer_get_phys(struct tahoe_dma_cfg *cfg,
|
|
unsigned long *addr)
|
|
{
|
|
int ret = 0;
|
|
if (cfg->paddr == 0)
|
|
{ /* only mapp once */
|
|
ret = tahoe_dma_buffer_map(cfg);
|
|
if (ret < 0) {
|
|
enc_pr(LOG_ERROR, "vpu_dma_buffer_map failed\n");
|
|
return ret;
|
|
}
|
|
}
|
|
if (cfg->paddr) *addr = cfg->paddr;
|
|
enc_pr(LOG_INFO,"vpu_dma_buffer_get_phys 0x%lx\n", cfg->paddr);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static s32 tahoe_src_addr_config(struct tahoe_dma_buf_info_t *pinfo,
|
|
struct file *filp)
|
|
{
|
|
struct tahoe_dma_buf_pool_t *vbp;
|
|
unsigned long phy_addr;
|
|
struct tahoe_dma_cfg *cfg;
|
|
s32 idx, ret = 0;
|
|
if (pinfo->num_planes == 0 || pinfo->num_planes > 3)
|
|
return -EFAULT;
|
|
|
|
for (idx = 0; idx < pinfo->num_planes; idx++)
|
|
pinfo->phys_addr[idx] = 0;
|
|
for (idx = 0; idx < pinfo->num_planes; idx++) {
|
|
vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);
|
|
if (!vbp) {
|
|
ret = -ENOMEM;
|
|
break;
|
|
}
|
|
memset(vbp, 0, sizeof(struct tahoe_dma_buf_pool_t));
|
|
cfg = &vbp->dma_cfg;
|
|
cfg->dir = DMA_TO_DEVICE;
|
|
cfg->fd = pinfo->fd[idx];
|
|
cfg->dev = &(tahoe_pdev->dev);
|
|
phy_addr = 0;
|
|
ret = tahoe_dma_buffer_get_phys(cfg, &phy_addr);
|
|
if (ret < 0) {
|
|
enc_pr(LOG_ERROR, "import fd %d failed\n", cfg->fd);
|
|
kfree(vbp);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
pinfo->phys_addr[idx] = (ulong) phy_addr;
|
|
vbp->filp = filp;
|
|
spin_lock(&s_dma_buf_lock);
|
|
list_add(&vbp->list, &s_dma_bufp_head);
|
|
spin_unlock(&s_dma_buf_lock);
|
|
}
|
|
enc_pr(LOG_INFO, "vpu_src_addr_config phy_addr 0x%lx, 0x%lx, 0x%lx\n",
|
|
pinfo->phys_addr[0], pinfo->phys_addr[1], pinfo->phys_addr[2]);
|
|
//hoan add for canvas test
|
|
#if 0
|
|
phys_addrY = pinfo->phys_addr[0];
|
|
phys_addrU = pinfo->phys_addr[1];
|
|
phys_addrV = pinfo->phys_addr[2];
|
|
#endif
|
|
|
|
//end
|
|
/*
|
|
* Variable vbp will free in vpu_dma_buf_release finally.
|
|
*/
|
|
/* coverity[leaked_storage] */
|
|
return ret;
|
|
}
|
|
|
|
static s32 tahoe_src_addr_unmap(struct tahoe_dma_buf_info_t *pinfo,
|
|
struct file *filp)
|
|
{
|
|
struct tahoe_dma_buf_pool_t *pool, *n;
|
|
struct tahoe_dma_cfg vb;
|
|
ulong phys_addr;
|
|
s32 plane_idx = 0;
|
|
s32 ret = 0;
|
|
s32 found;
|
|
|
|
if (pinfo->num_planes == 0 || pinfo->num_planes > 3)
|
|
return -EFAULT;
|
|
|
|
enc_pr(LOG_INFO,
|
|
"dma_unmap planes %d fd: %d-%d-%d, phy_add: 0x%lx-%lx-%lx\n",
|
|
pinfo->num_planes, pinfo->fd[0],pinfo->fd[1], pinfo->fd[2],
|
|
pinfo->phys_addr[0], pinfo->phys_addr[1], pinfo->phys_addr[2]);
|
|
|
|
list_for_each_entry_safe(pool, n, &s_dma_bufp_head, list) {
|
|
found = 0;
|
|
if (pool->filp == filp) {
|
|
vb = pool->dma_cfg;
|
|
phys_addr = vb.paddr;
|
|
if (vb.fd == pinfo->fd[0])
|
|
{
|
|
if (phys_addr != pinfo->phys_addr[0]) {
|
|
enc_pr(LOG_ERROR, "dma_unmap plane 0");
|
|
enc_pr(LOG_ERROR, " no match ");
|
|
enc_pr(LOG_ERROR, "0x%lx %lx\n",
|
|
phys_addr, pinfo->phys_addr[0]);
|
|
}
|
|
found = 1;
|
|
plane_idx++;
|
|
}
|
|
else if (vb.fd == pinfo->fd[1]
|
|
&& pinfo->num_planes > 1) {
|
|
if (phys_addr != pinfo->phys_addr[1]) {
|
|
enc_pr(LOG_ERROR, "dma_unmap plane 1");
|
|
enc_pr(LOG_ERROR, " no match ");
|
|
enc_pr(LOG_ERROR, "0x%lx %lx\n",
|
|
phys_addr, pinfo->phys_addr[1]);
|
|
}
|
|
plane_idx++;
|
|
found = 1;
|
|
}
|
|
else if (vb.fd == pinfo->fd[2]
|
|
&& pinfo->num_planes > 2) {
|
|
if (phys_addr != pinfo->phys_addr[2]) {
|
|
enc_pr(LOG_ERROR, "dma_unmap plane 2");
|
|
enc_pr(LOG_ERROR, " no match ");
|
|
enc_pr(LOG_ERROR, "0x%lx %lx\n",
|
|
phys_addr, pinfo->phys_addr[2]);
|
|
}
|
|
plane_idx++;
|
|
found = 1;
|
|
}
|
|
if (found && vb.attach) {
|
|
tahoe_dma_buffer_unmap(&vb);
|
|
spin_lock(&s_dma_buf_lock);
|
|
list_del(&pool->list);
|
|
spin_unlock(&s_dma_buf_lock);
|
|
kfree(pool);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plane_idx != pinfo->num_planes) {
|
|
enc_pr(LOG_DEBUG, "dma_unmap fd planes not match\n");
|
|
enc_pr(LOG_DEBUG, " found %d need %d\n",
|
|
plane_idx, pinfo->num_planes);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
static s32 tahoe_dma_buf_release(struct file *filp)
|
|
{
|
|
struct tahoe_dma_buf_pool_t *pool, *n;
|
|
struct tahoe_dma_cfg vb;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe_dma_buf_release\n");
|
|
list_for_each_entry_safe(pool, n, &s_dma_bufp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->dma_cfg;
|
|
if (vb.attach) {
|
|
tahoe_dma_buffer_unmap(&vb);
|
|
spin_lock(&s_dma_buf_lock);
|
|
list_del(&pool->list);
|
|
spin_unlock(&s_dma_buf_lock);
|
|
kfree(pool);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void tahoe_top_sw_reset(void)
|
|
{
|
|
WriteTahoeRegister(TAHOE_TOP_SW_RST, 0x3FFF);
|
|
WriteTahoeRegister(TAHOE_TOP_SW_RST, 0);
|
|
}
|
|
|
|
static s32 tahoe_open(struct inode *inode, struct file *filp)
|
|
{
|
|
bool first_open = false;
|
|
s32 r = 0;
|
|
|
|
//enc_pr(LOG_DEBUG, "[+] %s, filp=%lu, %lu, f_count=%lld\n", __func__,
|
|
//(unsigned long)filp, ( ((unsigned long)filp)%8), filp->f_count.counter);
|
|
spin_lock(&s_vpu_lock);
|
|
s_tahoe_drv_context.open_count++;
|
|
if (s_tahoe_drv_context.open_count == 1) {
|
|
first_open = true;
|
|
}
|
|
init_waitqueue_head(&s_tahoe_drv_context.request_complete);
|
|
atomic_set(&s_tahoe_drv_context.request_ready, 0);
|
|
filp->private_data = (void *)(&s_tahoe_drv_context);
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
if (first_open) {
|
|
if ((s_tahoe_irq >= 0) && (s_tahoe_irq_requested == false)) {
|
|
s32 err;
|
|
|
|
err = request_irq(s_tahoe_irq, tahoe_irq_handler, 0, "tahoe_irq0", (void *)(&s_tahoe_drv_context));
|
|
|
|
if (err) {
|
|
enc_pr(LOG_ERROR, "Failed to register irq handler\n");
|
|
spin_lock(&s_vpu_lock);
|
|
s_tahoe_drv_context.open_count--;
|
|
spin_unlock(&s_vpu_lock);
|
|
return -EFAULT;
|
|
}
|
|
|
|
s_tahoe_irq_requested = true;
|
|
}
|
|
|
|
/* enable tahoe clks and power*/
|
|
tahoe_clk_enable(&s_tahoe_clks);
|
|
tahoe_top_sw_reset();
|
|
}
|
|
|
|
if (r != 0) {
|
|
spin_lock(&s_vpu_lock);
|
|
s_tahoe_drv_context.open_count--;
|
|
spin_unlock(&s_vpu_lock);
|
|
}
|
|
|
|
enc_pr(LOG_DEBUG, "[-] %s, ret: %d\n", __func__, r);
|
|
return r;
|
|
}
|
|
|
|
static s32 tahoe_release(struct inode *inode, struct file *filp)
|
|
{
|
|
s32 ret = 0;
|
|
u32 open_count;
|
|
int i;
|
|
|
|
//enc_pr(LOG_DEBUG, "vpu_release filp=%lu, f_counter=%ld\n",
|
|
//(unsigned long)filp, filp->f_count.counter);
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
|
|
if (ret == 0) {
|
|
/* found and free the not handled
|
|
buffer by user applications */
|
|
tahoe_free_buffers(filp);
|
|
tahoe_dma_buf_release(filp);
|
|
//tahoe_dma_buf_release(filp); //__need_modify__
|
|
|
|
spin_lock(&s_vpu_lock);
|
|
s_tahoe_drv_context.open_count--;
|
|
open_count = s_tahoe_drv_context.open_count;
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
enc_pr(LOG_INFO, "open_count=%u\n", open_count);
|
|
|
|
if (open_count == 0) {
|
|
s_tahoe_drv_context.interrupt_reason = 0;
|
|
s_tahoe_drv_context.interrupt_flag = 0;
|
|
|
|
for (i = 0; i < MAX_INSTANCE; i++) {
|
|
if (s_video_memory[i].phys_addr && !use_reserve) {
|
|
enc_pr(LOG_DEBUG,
|
|
"tahoe_release, s_video_memory 0x%lx\n",
|
|
s_video_memory[i].phys_addr);
|
|
codec_mm_free_for_dma(
|
|
DEVICE_NAME,
|
|
s_video_memory[i].phys_addr);
|
|
memset(&s_video_memory[i],
|
|
0, sizeof(struct venc_drv_common_buffer_t));
|
|
}
|
|
}
|
|
if (fw_buffer.phys_addr) {
|
|
enc_pr(LOG_DEBUG,
|
|
"tahoe_release, fw_buffer.phys_addr 0x%lx\n",
|
|
fw_buffer.phys_addr);
|
|
codec_mm_free_for_dma(
|
|
DEVICE_NAME,
|
|
fw_buffer.phys_addr);
|
|
memset(&fw_buffer,
|
|
0, sizeof(struct venc_drv_buffer_t));
|
|
}
|
|
|
|
if ((s_tahoe_irq >= 0)
|
|
&& (s_tahoe_irq_requested == true)) {
|
|
free_irq(s_tahoe_irq, &s_tahoe_drv_context);
|
|
s_tahoe_irq_requested = false;
|
|
}
|
|
|
|
/* disable tahoe clks.*/
|
|
tahoe_clk_disable(&s_tahoe_clks);
|
|
}
|
|
}
|
|
up(&s_vpu_sem);
|
|
return 0;
|
|
}
|
|
|
|
static s32 tahoe_mmap(struct file *filp, struct vm_area_struct *vma)
|
|
{
|
|
ulong vm_size = (unsigned long)(vma->vm_end - vma->vm_start);
|
|
|
|
/*if (vma->vm_pgoff == fw_buffer.phys_addr >> PAGE_SHIFT) {
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
} else {*/
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); //__need_modify__
|
|
//}
|
|
return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vm_size, vma->vm_page_prot) ? -EAGAIN : 0;
|
|
}
|
|
|
|
static s32 tahoe_alloc_dma_buffer(struct venc_drv_buffer_t *vb)
|
|
{
|
|
if (!vb)
|
|
return -1;
|
|
|
|
vb->phys_addr = (ulong)codec_mm_alloc_for_dma(DEVICE_NAME, PAGE_ALIGN(vb->size) >> PAGE_SHIFT, 0, 0);
|
|
if (vb->phys_addr == 0) {
|
|
enc_pr(LOG_ERROR,
|
|
"Physical memory allocation error size=%d\n",
|
|
vb->size);
|
|
return -1;
|
|
}
|
|
|
|
enc_pr(LOG_INFO,
|
|
"%s: vb->phys_addr 0x%lx\n", __func__,
|
|
vb->phys_addr);
|
|
return 0;
|
|
}
|
|
static void tahoe_free_dma_buffer(struct venc_drv_buffer_t *vb)
|
|
{
|
|
if (!vb)
|
|
return;
|
|
enc_pr(LOG_INFO, "tahoe_free_dma_buffer 0x%lx\n",vb->phys_addr);
|
|
|
|
if (vb->phys_addr)
|
|
codec_mm_free_for_dma(DEVICE_NAME, vb->phys_addr);
|
|
}
|
|
|
|
static s32 tahoe_free_buffers(struct file *filp)
|
|
{
|
|
struct venc_drv_buffer_pool_t *pool, *n;
|
|
struct venc_drv_buffer_t vb;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe_free_buffers\n");
|
|
list_for_each_entry_safe(pool, n, &s_vbp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->vb;
|
|
if (vb.phys_addr) {
|
|
tahoe_free_dma_buffer(&vb);
|
|
spin_lock(&s_vpu_lock);
|
|
list_del(&pool->list);
|
|
spin_unlock(&s_vpu_lock);
|
|
kfree(pool);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static long tahoe_ioctl(struct file *filp, u32 cmd, ulong arg)
|
|
{
|
|
s32 ret = 0;
|
|
struct venc_drv_context_t *dev = (struct venc_drv_context_t *)filp->private_data;
|
|
|
|
switch (cmd)
|
|
{
|
|
case IOC_GET_REGISTER_INFO:
|
|
{
|
|
enc_pr(LOG_ALL, "[+]IOC_GET_REGISTER_INFO\n");
|
|
ret = copy_to_user((void __user *)arg, &s_tahoe_register, sizeof(struct venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
enc_pr(LOG_ALL, "[-]IOC_GET_REGISTER_INFO\n");
|
|
}
|
|
break;
|
|
|
|
case IOC_GET_COMMON_BUF_INFO:
|
|
{
|
|
int chnid;
|
|
struct venc_drv_common_buffer_t info;
|
|
|
|
enc_pr(LOG_ALL, "[+]IOC_GET_COMMON_BUF_INFO\n");
|
|
ret = copy_from_user(&info, (struct venc_drv_common_buffer_t *)arg, sizeof(struct venc_drv_common_buffer_t));
|
|
if (ret != 0)
|
|
return -EFAULT;
|
|
|
|
chnid = info.chnid;
|
|
if (chnid < 0 || chnid >= MAX_INSTANCE)
|
|
return -EFAULT;
|
|
|
|
s_video_memory[chnid].chnid = chnid;
|
|
if (s_video_memory[chnid].phys_addr != 0) {
|
|
ret = copy_to_user((void __user *)arg,
|
|
&s_video_memory[chnid],
|
|
sizeof(struct venc_drv_common_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
} else {
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
s_video_memory[chnid].size = cma_cfg_size;
|
|
s_video_memory[chnid].phys_addr = (ulong)codec_mm_alloc_for_dma(DEVICE_NAME, cma_cfg_size >> PAGE_SHIFT, 0, 0);
|
|
|
|
if (s_video_memory[chnid].phys_addr) {
|
|
s_video_memory[chnid].base = s_video_memory[chnid].phys_addr;
|
|
enc_pr(LOG_DEBUG, "allocating phys 0x%lx, ", s_video_memory[chnid].phys_addr);
|
|
enc_pr(LOG_DEBUG, "virt addr 0x%lx, size %dk\n", s_video_memory[chnid].base, s_video_memory[chnid].size >> 10);
|
|
} else {
|
|
enc_pr(LOG_ERROR, "Failed to alloc dma buffer %s, phys:0x%lx\n", DEVICE_NAME, s_video_memory[chnid].phys_addr);
|
|
|
|
if (s_video_memory[chnid].phys_addr)
|
|
codec_mm_free_for_dma(DEVICE_NAME, s_video_memory[chnid].phys_addr);
|
|
|
|
s_video_memory[chnid].phys_addr = 0;
|
|
ret = -ENOMEM;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
ret = copy_to_user((void __user *)arg,
|
|
&s_video_memory[chnid],
|
|
sizeof(struct venc_drv_common_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
up(&s_vpu_sem);
|
|
}
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_GET_COMMON_BUF_INFO\n");
|
|
}
|
|
break;
|
|
#ifdef CONFIG_COMPAT
|
|
case IOC_GET_COMMON_BUF_INFO32:
|
|
{
|
|
struct compat_venc_drv_buffer_t buf32;
|
|
int chnid;
|
|
struct venc_drv_common_buffer_t info;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_GET_COMMON_BUF_INFO32\n");
|
|
|
|
ret = copy_from_user(&info, (struct venc_drv_common_buffer_t *)arg, sizeof(struct venc_drv_common_buffer_t));
|
|
if (ret != 0)
|
|
return -EFAULT;
|
|
|
|
chnid = info.chnid;
|
|
if (chnid < 0 || chnid >= MAX_INSTANCE)
|
|
return -EFAULT;
|
|
|
|
s_video_memory[chnid].chnid = chnid;
|
|
memset(&buf32, 0, sizeof(struct compat_venc_drv_buffer_t));
|
|
buf32.size = s_video_memory[chnid].size;
|
|
buf32.phys_addr =
|
|
(compat_ulong_t)
|
|
s_video_memory[chnid].phys_addr;
|
|
buf32.virt_addr =
|
|
(compat_ulong_t)
|
|
s_video_memory[chnid].virt_addr;
|
|
if (s_video_memory[chnid].phys_addr != 0) {
|
|
ret = copy_to_user((void __user *)arg,
|
|
&buf32,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
} else {
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
s_video_memory[chnid].size = cma_cfg_size;
|
|
s_video_memory[chnid].phys_addr = (ulong)codec_mm_alloc_for_dma(DEVICE_NAME, cma_cfg_size >> PAGE_SHIFT, 0, 0);
|
|
|
|
if (s_video_memory[chnid].phys_addr) {
|
|
s_video_memory[chnid].base = s_video_memory[chnid].phys_addr;
|
|
enc_pr(LOG_DEBUG, "allocating phys 0x%lx, ", s_video_memory[chnid].phys_addr);
|
|
enc_pr(LOG_DEBUG, "virt addr 0x%lx, size %dk\n", s_video_memory[chnid].base, s_video_memory[chnid].size >> 10);
|
|
} else {
|
|
enc_pr(LOG_ERROR, "Failed to alloc dma buffer %s, phys:0x%lx\n", DEVICE_NAME, s_video_memory[chnid].phys_addr);
|
|
|
|
if (s_video_memory[chnid].phys_addr)
|
|
codec_mm_free_for_dma(DEVICE_NAME, s_video_memory[chnid].phys_addr);
|
|
|
|
s_video_memory[chnid].phys_addr = 0;
|
|
ret = -ENOMEM;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
|
|
buf32.size = s_video_memory[chnid].size;
|
|
buf32.phys_addr =
|
|
(compat_ulong_t)
|
|
s_video_memory[chnid].phys_addr;
|
|
buf32.virt_addr =
|
|
(compat_ulong_t)
|
|
s_video_memory[chnid].virt_addr;
|
|
ret = copy_to_user((void __user *)arg,
|
|
&buf32, sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
|
|
up(&s_vpu_sem);
|
|
}
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_GET_COMMON_BUF_INFO32\n");
|
|
}
|
|
break;
|
|
#endif
|
|
case IOC_WAIT_INTERRUPT:
|
|
{
|
|
struct venc_drv_intr_info_t info;
|
|
enc_pr(LOG_ALL, "[+]IOC_WAIT_INTERRUPT\n");
|
|
|
|
ret = copy_from_user(&info, (struct venc_drv_intr_info_t *)arg, sizeof(struct venc_drv_intr_info_t));
|
|
if (ret != 0)
|
|
{
|
|
return -EFAULT;
|
|
}
|
|
ret = wait_event_interruptible_timeout(s_interrupt_wait_q, s_interrupt_flag != 0, msecs_to_jiffies(info.timeout));
|
|
|
|
info.intr_reason = dev->interrupt_reason;
|
|
s_interrupt_flag = 0;
|
|
dev->interrupt_reason = 0;
|
|
|
|
ret = copy_to_user((void __user *)arg, &info, sizeof(struct venc_drv_intr_info_t));
|
|
if (ret != 0)
|
|
{
|
|
return -EFAULT;
|
|
}
|
|
enc_pr(LOG_ALL, "[-]IOC_WAIT_INTERRUPT\n");
|
|
}
|
|
break;
|
|
case IOC_GET_FW_BUF_INFO:
|
|
{
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_GET_FW_BUF_INFO\n");
|
|
if (fw_buffer.phys_addr != 0) {
|
|
ret = copy_to_user((void __user *)arg,
|
|
&fw_buffer,
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
} else {
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
fw_buffer.size = MC_SIZE;
|
|
fw_buffer.phys_addr = (ulong)codec_mm_alloc_for_dma(DEVICE_NAME, PAGE_ALIGN(fw_buffer.size) >> PAGE_SHIFT, 0, 0);
|
|
|
|
if (fw_buffer.phys_addr) {
|
|
fw_buffer.base = fw_buffer.phys_addr;
|
|
enc_pr(LOG_DEBUG, "allocating phys 0x%lx, ", fw_buffer.phys_addr);
|
|
enc_pr(LOG_DEBUG, "virt addr 0x%lx, size %dk\n", fw_buffer.virt_addr, fw_buffer.size >> 10);
|
|
} else {
|
|
enc_pr(LOG_ERROR, "Failed to alloc dma buffer %s, phys:0x%lx\n", DEVICE_NAME, fw_buffer.phys_addr);
|
|
|
|
if (fw_buffer.phys_addr)
|
|
codec_mm_free_for_dma(DEVICE_NAME, fw_buffer.phys_addr);
|
|
|
|
fw_buffer.phys_addr = 0;
|
|
|
|
ret = -ENOMEM;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
ret = copy_to_user((void __user *)arg,
|
|
&fw_buffer,
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
up(&s_vpu_sem);
|
|
}
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_GET_FW_BUF_INFO\n");
|
|
}
|
|
break;
|
|
#ifdef CONFIG_COMPAT
|
|
case IOC_GET_FW_BUF_INFO32:
|
|
{
|
|
struct compat_venc_drv_buffer_t buf32;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_GET_FW_BUF_INFO32\n");
|
|
|
|
memset(&buf32, 0, sizeof(struct compat_venc_drv_buffer_t));
|
|
buf32.size = fw_buffer.size;
|
|
buf32.phys_addr =
|
|
(compat_ulong_t)
|
|
fw_buffer.phys_addr;
|
|
buf32.virt_addr =
|
|
(compat_ulong_t)
|
|
fw_buffer.virt_addr;
|
|
if (fw_buffer.phys_addr != 0) {
|
|
ret = copy_to_user((void __user *)arg,
|
|
&buf32,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
} else {
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
fw_buffer.size = MC_SIZE;
|
|
fw_buffer.phys_addr = (ulong)codec_mm_alloc_for_dma(DEVICE_NAME, fw_buffer.size >> PAGE_SHIFT, 0, 0);
|
|
|
|
if (fw_buffer.phys_addr) {
|
|
fw_buffer.base = fw_buffer.phys_addr;
|
|
enc_pr(LOG_DEBUG, "allocating phys 0x%lx, ", fw_buffer.phys_addr);
|
|
enc_pr(LOG_DEBUG, "virt addr 0x%lx, size %dk\n", fw_buffer.virt_addr, fw_buffer.size >> 10);
|
|
} else {
|
|
enc_pr(LOG_ERROR, "Failed to alloc dma buffer %s, phys:0x%lx\n", DEVICE_NAME, fw_buffer.phys_addr);
|
|
|
|
if (fw_buffer.phys_addr)
|
|
codec_mm_free_for_dma(DEVICE_NAME, fw_buffer.phys_addr);
|
|
|
|
fw_buffer.phys_addr = 0;
|
|
ret = -ENOMEM;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
|
|
buf32.size =
|
|
fw_buffer.size;
|
|
buf32.phys_addr =
|
|
(compat_ulong_t)
|
|
fw_buffer.phys_addr;
|
|
buf32.virt_addr =
|
|
(compat_ulong_t)
|
|
fw_buffer.virt_addr;
|
|
ret = copy_to_user((void __user *)arg,
|
|
&buf32, sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret != 0)
|
|
ret = -EFAULT;
|
|
|
|
up(&s_vpu_sem);
|
|
}
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_GET_FW_BUF_INFO32\n");
|
|
}
|
|
break;
|
|
#endif
|
|
case IOC_ALLOCATE_PHYSICAL_MEMORY:
|
|
{
|
|
struct venc_drv_buffer_pool_t *vbp;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_ALLOCATE_PHYSICAL_MEMORY\n");
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret == 0) {
|
|
vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);
|
|
if (!vbp) {
|
|
up(&s_vpu_sem);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = copy_from_user(&(vbp->vb),
|
|
(struct venc_drv_buffer_t *)arg,
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret) {
|
|
kfree(vbp);
|
|
up(&s_vpu_sem);
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = tahoe_alloc_dma_buffer(&(vbp->vb));
|
|
if (ret == -1) {
|
|
ret = -ENOMEM;
|
|
kfree(vbp);
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
ret = copy_to_user((void __user *)arg,
|
|
&(vbp->vb),
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret) {
|
|
kfree(vbp);
|
|
ret = -EFAULT;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
|
|
vbp->filp = filp;
|
|
spin_lock(&s_vpu_lock);
|
|
list_add(&vbp->list, &s_vbp_head);
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
up(&s_vpu_sem);
|
|
}
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_ALLOCATE_PHYSICAL_MEMORY\n");
|
|
}
|
|
break;
|
|
#ifdef CONFIG_COMPAT
|
|
case IOC_ALLOCATE_PHYSICAL_MEMORY32:
|
|
{
|
|
struct venc_drv_buffer_pool_t *vbp;
|
|
struct compat_venc_drv_buffer_t buf32;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_ALLOCATE_PHYSICAL_MEMORY32\n");
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret == 0) {
|
|
vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);
|
|
if (!vbp) {
|
|
up(&s_vpu_sem);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = copy_from_user(&buf32,
|
|
(struct compat_venc_drv_buffer_t *)arg,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret) {
|
|
kfree(vbp);
|
|
up(&s_vpu_sem);
|
|
return -EFAULT;
|
|
}
|
|
|
|
vbp->vb.size = buf32.size;
|
|
vbp->vb.cached = buf32.cached;
|
|
vbp->vb.phys_addr =
|
|
(ulong)buf32.phys_addr;
|
|
vbp->vb.virt_addr =
|
|
(ulong)buf32.virt_addr;
|
|
ret = tahoe_alloc_dma_buffer(&(vbp->vb));
|
|
if (ret == -1) {
|
|
ret = -ENOMEM;
|
|
kfree(vbp);
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
|
|
buf32.size = vbp->vb.size;
|
|
buf32.phys_addr =
|
|
(compat_ulong_t)vbp->vb.phys_addr;
|
|
buf32.virt_addr =
|
|
(compat_ulong_t)vbp->vb.virt_addr;
|
|
|
|
ret = copy_to_user((void __user *)arg,
|
|
&buf32,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret) {
|
|
kfree(vbp);
|
|
ret = -EFAULT;
|
|
up(&s_vpu_sem);
|
|
break;
|
|
}
|
|
|
|
vbp->filp = filp;
|
|
spin_lock(&s_vpu_lock);
|
|
list_add(&vbp->list, &s_vbp_head);
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
up(&s_vpu_sem);
|
|
}
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_ALLOCATE_PHYSICAL_MEMORY32\n");
|
|
}
|
|
break;
|
|
#endif
|
|
case IOC_FLUSH_BUFFER:
|
|
{
|
|
struct venc_drv_buffer_pool_t *pool, *n;
|
|
struct venc_drv_buffer_t vb, buf;
|
|
bool find = false;
|
|
u32 cached = 0;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_FLUSH_BUFFER\n");
|
|
|
|
ret = copy_from_user(&buf,
|
|
(struct venc_drv_buffer_t *)arg,
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
spin_lock(&s_vpu_lock);
|
|
list_for_each_entry_safe(pool, n,
|
|
&s_vbp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->vb;
|
|
if ((vb.phys_addr <= buf.phys_addr)
|
|
&& ((vb.phys_addr + vb.size)
|
|
> buf.phys_addr)
|
|
&& find == false){
|
|
cached = vb.cached;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
spin_unlock(&s_vpu_lock);
|
|
if (find && cached)
|
|
dma_flush(
|
|
(u32)buf.phys_addr,
|
|
(u32)buf.size);
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_FLUSH_BUFFER\n");
|
|
}
|
|
break;
|
|
case IOC_CACHE_INV_BUFFER:
|
|
{
|
|
struct venc_drv_buffer_t buf;
|
|
struct venc_drv_buffer_pool_t *pool, *n;
|
|
struct venc_drv_buffer_t vb;
|
|
bool find = false;
|
|
u32 cached = 0;
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_CACHE_INV_BUFFER\n");
|
|
|
|
ret = copy_from_user(&buf,
|
|
(struct venc_drv_buffer_t *)arg,
|
|
sizeof(struct venc_drv_buffer_t));
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
spin_lock(&s_vpu_lock);
|
|
list_for_each_entry_safe(pool, n, &s_vbp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->vb;
|
|
if ((vb.phys_addr <= buf.phys_addr) && ((vb.phys_addr + vb.size) > buf.phys_addr) && find == false) {
|
|
cached = vb.cached;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
spin_unlock(&s_vpu_lock);
|
|
if (find && cached) {
|
|
enc_pr(LOG_INFO, "[%d]doing cache flush for 0x%lx~0x%lx\n", __LINE__, (long)(buf.phys_addr), (long)(buf.phys_addr+buf.size));
|
|
cache_flush((u32)buf.phys_addr,(u32)buf.size);
|
|
}
|
|
|
|
enc_pr(LOG_ALL,"[-]IOC_CACHE_INV_BUFFER\n");
|
|
}
|
|
break;
|
|
#ifdef CONFIG_COMPAT
|
|
case IOC_FLUSH_BUFFER32:
|
|
{
|
|
struct venc_drv_buffer_pool_t *pool, *n;
|
|
struct compat_venc_drv_buffer_t buf32;
|
|
struct venc_drv_buffer_t vb;
|
|
bool find = false;
|
|
u32 cached = 0;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_FLUSH_BUFFER32\n");
|
|
|
|
ret = copy_from_user(&buf32,
|
|
(struct compat_venc_drv_buffer_t *)arg,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
spin_lock(&s_vpu_lock);
|
|
list_for_each_entry_safe(pool, n,
|
|
&s_vbp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->vb;
|
|
if (((compat_ulong_t)vb.phys_addr <=
|
|
buf32.phys_addr) &&
|
|
(((compat_ulong_t)vb.phys_addr
|
|
+ vb.size)
|
|
> buf32.phys_addr)
|
|
&& find == false){
|
|
cached = vb.cached;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
if (find && cached)
|
|
dma_flush(
|
|
(u32)buf32.phys_addr,
|
|
(u32)buf32.size);
|
|
enc_pr(LOG_ALL,
|
|
"[-]IOC_FLUSH_BUFFER32\n");
|
|
}
|
|
break;
|
|
case IOC_CACHE_INV_BUFFER32:
|
|
{
|
|
struct compat_venc_drv_buffer_t buf32;
|
|
struct venc_drv_buffer_pool_t *pool, *n;
|
|
struct venc_drv_buffer_t vb;
|
|
bool find = false;
|
|
u32 cached = 0;
|
|
enc_pr(LOG_ALL, "[+]IOC_CACHE_INV_BUFFER32\n");
|
|
|
|
ret = copy_from_user(&buf32,
|
|
(struct compat_venc_drv_buffer_t *)arg,
|
|
sizeof(struct compat_venc_drv_buffer_t));
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
spin_lock(&s_vpu_lock);
|
|
list_for_each_entry_safe(pool, n,
|
|
&s_vbp_head, list) {
|
|
if (pool->filp == filp) {
|
|
vb = pool->vb;
|
|
if (((compat_ulong_t)vb.phys_addr
|
|
<= buf32.phys_addr)
|
|
&& (((compat_ulong_t)vb.phys_addr +
|
|
vb.size) > buf32.phys_addr)
|
|
&& find == false){
|
|
cached = vb.cached;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
if (find && cached) {
|
|
cache_flush((u32)buf32.phys_addr, (u32)buf32.size);
|
|
|
|
/*if (dump_es) {
|
|
enc_pr(LOG_INFO, "dump es frame, size=%u\n", (u32)buf32.size);
|
|
dump_data((u32)buf32.phys_addr, (u32)buf32.size);
|
|
}*/
|
|
}
|
|
enc_pr(LOG_INFO, "[-]IOC_CACHE_INV_BUFFER32\n");
|
|
}
|
|
break;
|
|
#endif
|
|
case IOC_NR_FOR_DEBUG:
|
|
{
|
|
u32 data = 0;
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_NR_FOR_DEBUG\n");
|
|
|
|
if (get_user(data, (u32 __user *) arg))
|
|
return -EFAULT;
|
|
enc_pr(LOG_INFO, "============add_for_debug data:%d\n", data);
|
|
|
|
enc_pr(LOG_ALL,"[-]IOC_NR_FOR_DEBUG\n");
|
|
}
|
|
break;
|
|
case IOC_CONFIG_DMA:
|
|
{
|
|
struct tahoe_dma_buf_info_t dma_info;
|
|
enc_pr(LOG_DEBUG,
|
|
"[+]IOC_CONFIG_DMA\n");
|
|
|
|
if (copy_from_user(&dma_info,
|
|
(struct tahoe_dma_buf_info_t *)arg,
|
|
sizeof(struct tahoe_dma_buf_info_t)))
|
|
return -EFAULT;
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
if (tahoe_src_addr_config(&dma_info, filp)) {
|
|
up(&s_vpu_sem);
|
|
enc_pr(LOG_ERROR,
|
|
"src addr config error\n");
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
up(&s_vpu_sem);
|
|
ret = copy_to_user((void __user *)arg,
|
|
&dma_info,
|
|
sizeof(struct tahoe_dma_buf_info_t));
|
|
if (ret) {
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
enc_pr(LOG_DEBUG,
|
|
"[-]IOC_CONFIG_DMA %d, %d, %d\n",
|
|
dma_info.fd[0],
|
|
dma_info.fd[1],
|
|
dma_info.fd[2]);
|
|
}
|
|
break;
|
|
case IOC_UNMAP_DMA:
|
|
{
|
|
struct tahoe_dma_buf_info_t dma_info;
|
|
|
|
enc_pr(LOG_ALL,
|
|
"[+]IOC_UNMAP_DMA\n");
|
|
|
|
if (copy_from_user(&dma_info,
|
|
(struct tahoe_dma_buf_info_t *)arg,
|
|
sizeof(struct tahoe_dma_buf_info_t)))
|
|
return -EFAULT;
|
|
ret = down_interruptible(&s_vpu_sem);
|
|
if (ret != 0)
|
|
break;
|
|
if (tahoe_src_addr_unmap(&dma_info, filp)) {
|
|
up(&s_vpu_sem);
|
|
enc_pr(LOG_ERROR,
|
|
"dma addr unmap config error\n");
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
up(&s_vpu_sem);
|
|
enc_pr(LOG_ALL,
|
|
"[-]VDI_IOCTL_UNMAP_DMA\n");
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
enc_pr(LOG_ALL, "tahoe_ioctl end\n");
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
static long tahoe_compat_ioctl(struct file *filp, u32 cmd, ulong arg)
|
|
{
|
|
long ret;
|
|
|
|
arg = (ulong)compat_ptr(arg);
|
|
ret = tahoe_ioctl(filp, cmd, arg);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static u32 tahoe_poll(struct file *file, poll_table *wait_table)
|
|
{
|
|
struct venc_drv_context_t *s_context = (struct venc_drv_context_t *)file->private_data;;
|
|
|
|
poll_wait(file, &s_context->request_complete, wait_table);
|
|
|
|
if (atomic_read(&s_context->request_ready)) {
|
|
atomic_dec(&s_context->request_ready);
|
|
return POLLIN | POLLRDNORM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations tahoe_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = tahoe_open,
|
|
.release = tahoe_release,
|
|
.unlocked_ioctl = tahoe_ioctl,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = tahoe_compat_ioctl,
|
|
#endif
|
|
.mmap = tahoe_mmap,
|
|
.poll = tahoe_poll,
|
|
};
|
|
|
|
static ssize_t chip_id_show(KV_CLASS_CONST struct class *cla,
|
|
KV_CLASS_ATTR_CONST struct class_attribute *attr, char *buf)
|
|
{
|
|
//char *pbuf = buf;
|
|
//pbuf += sprintf(pbuf, "Chip ID: 0x%08x\n", ReadTahoeRegister(CHIP_ID));
|
|
//return pbuf - buf;
|
|
return 0;
|
|
}
|
|
|
|
static CLASS_ATTR_RO(chip_id);
|
|
static struct attribute *tahoe_class_attrs[] = {
|
|
&class_attr_chip_id.attr,
|
|
NULL
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(tahoe_class);
|
|
static struct class tahoe_class = {
|
|
.name = CLASS_NAME,
|
|
.class_groups = tahoe_class_groups,
|
|
};
|
|
|
|
s32 init_tahoe_device(void)
|
|
{
|
|
s32 r = 0;
|
|
|
|
r = register_chrdev(0, DEVICE_NAME, &tahoe_fops);
|
|
if (r <= 0) {
|
|
enc_pr(LOG_ERROR, "register tahoe device error.\n");
|
|
return r;
|
|
}
|
|
s_tahoe_major = r;
|
|
|
|
r = class_register(&tahoe_class);
|
|
if (r < 0) {
|
|
enc_pr(LOG_ERROR, "error create tahoe class.\n");
|
|
return r;
|
|
}
|
|
s_register_flag = 1;
|
|
tahoe_dev = device_create(&tahoe_class, NULL,
|
|
MKDEV(s_tahoe_major, 0), NULL,
|
|
DEVICE_NAME);
|
|
|
|
if (IS_ERR(tahoe_dev)) {
|
|
enc_pr(LOG_ERROR, "create create device error.\n");
|
|
class_unregister(&tahoe_class);
|
|
return -1;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
s32 uninit_tahoe_device(void)
|
|
{
|
|
if (tahoe_dev)
|
|
device_destroy(&tahoe_class, MKDEV(s_tahoe_major, 0));
|
|
|
|
if (s_register_flag)
|
|
class_destroy(&tahoe_class);
|
|
s_register_flag = 0;
|
|
|
|
if (s_tahoe_major)
|
|
unregister_chrdev(s_tahoe_major, DEVICE_NAME);
|
|
s_tahoe_major = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void tahoe_hw_reset(void)
|
|
{
|
|
if (IS_ERR(s_tahoe_rsts.core_rst) ||
|
|
IS_ERR(s_tahoe_rsts.a_rst) ||
|
|
IS_ERR(s_tahoe_rsts.apb_rst) ||
|
|
IS_ERR(s_tahoe_rsts.sys_rst)) {
|
|
return;
|
|
}
|
|
reset_control_reset(s_tahoe_rsts.core_rst);
|
|
reset_control_reset(s_tahoe_rsts.a_rst);
|
|
reset_control_reset(s_tahoe_rsts.apb_rst);
|
|
reset_control_reset(s_tahoe_rsts.sys_rst);
|
|
}
|
|
|
|
static void tahoe_clk_put(struct device *dev, struct tahoe_clks *clks)
|
|
{
|
|
if (!(clks->sys_tahoe == NULL || IS_ERR(clks->sys_tahoe)))
|
|
devm_clk_put(dev, clks->sys_tahoe);
|
|
if (!(clks->tahoe_clk == NULL || IS_ERR(clks->tahoe_clk)))
|
|
devm_clk_put(dev, clks->tahoe_clk);
|
|
}
|
|
|
|
static int tahoe_clk_get(struct device *dev, struct tahoe_clks *clks)
|
|
{
|
|
int ret = 0;
|
|
|
|
clks->sys_tahoe = devm_clk_get(dev, "sys_tahoe");
|
|
|
|
if (IS_ERR(clks->sys_tahoe)) {
|
|
enc_pr(LOG_ERROR, "cannot get sys_tahoe clock\n");
|
|
clks->sys_tahoe = NULL;
|
|
//ret = -ENOENT;
|
|
//goto err;
|
|
}
|
|
clks->tahoe_clk = devm_clk_get(dev, "clk_tahoe");
|
|
|
|
if (IS_ERR(clks->tahoe_clk)) {
|
|
enc_pr(LOG_ERROR, "cannot get clk_tahoe clock\n");
|
|
clks->tahoe_clk = NULL;
|
|
ret = -ENOENT;
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
tahoe_clk_put(dev, clks);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int tahoe_rst_get(struct device *dev, struct tahoe_rsts *rsts)
|
|
{
|
|
//int ret = 0;
|
|
|
|
rsts->core_rst = devm_reset_control_get(dev, "tahoe_core_rst");
|
|
|
|
if (IS_ERR(rsts->core_rst)) {
|
|
enc_pr(LOG_ERROR, "cannot get core_rst\n");
|
|
rsts->core_rst = NULL;
|
|
//ret = -ENOENT;
|
|
//goto err;
|
|
}
|
|
|
|
rsts->a_rst = devm_reset_control_get(dev, "tahoe_a_rst");
|
|
|
|
if (IS_ERR(rsts->a_rst)) {
|
|
enc_pr(LOG_ERROR, "cannot get a_rst\n");
|
|
rsts->a_rst = NULL;
|
|
//ret = -ENOENT;
|
|
//goto err;
|
|
}
|
|
|
|
rsts->apb_rst = devm_reset_control_get(dev, "tahoe_apb_rst");
|
|
|
|
if (IS_ERR(rsts->apb_rst)) {
|
|
enc_pr(LOG_ERROR, "cannot get apb_rst\n");
|
|
rsts->apb_rst = NULL;
|
|
//ret = -ENOENT;
|
|
//goto err;
|
|
}
|
|
|
|
rsts->sys_rst = devm_reset_control_get(dev, "tahoe_sys_rst");
|
|
|
|
if (IS_ERR(rsts->sys_rst)) {
|
|
enc_pr(LOG_ERROR, "cannot get sys_rst\n");
|
|
rsts->sys_rst = NULL;
|
|
//ret = -ENOENT;
|
|
//goto err;
|
|
}
|
|
return 0;
|
|
//err:
|
|
//return ret;
|
|
}
|
|
|
|
static void tahoe_clk_enable(struct tahoe_clks *clks)
|
|
{
|
|
if (clks->sys_tahoe != NULL) {
|
|
clk_prepare_enable(clks->sys_tahoe);
|
|
}
|
|
if (clock_a > 0) {
|
|
enc_pr(LOG_INFO, "tahoe: desired clock_a freq %u\n", clock_a);
|
|
clk_set_rate(clks->tahoe_clk, clock_a);
|
|
} else
|
|
clk_set_rate(clks->tahoe_clk, 666666666);
|
|
|
|
clk_prepare_enable(clks->tahoe_clk);
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe: %ld\n", clk_get_rate(clks->tahoe_clk));
|
|
|
|
/* the power on*/
|
|
pm_runtime_get_sync(&tahoe_pdev->dev);
|
|
mdelay(5);
|
|
enc_pr(LOG_INFO, "tahoe power stauts after poweron: %d\n", pm_runtime_active(&tahoe_pdev->dev));
|
|
|
|
/* reset */
|
|
tahoe_hw_reset(); //__need_modify__
|
|
/* gate the clocks */
|
|
#ifdef TAHOE_SUPPORT_CLOCK_CONTROL
|
|
enc_pr(LOG_INFO, "tahoe_clk_enable, now gate off the clock\n");
|
|
clk_disable(clks->tahoe_clk);
|
|
#endif
|
|
}
|
|
|
|
static void tahoe_clk_disable(struct tahoe_clks *clks)
|
|
{
|
|
#ifdef TAHOE_SUPPORT_CLOCK_CONTROL
|
|
if (clock_gate_count > 0)
|
|
#endif
|
|
{
|
|
enc_pr(LOG_INFO, "tahoe unclosed clock %d\n", clock_gate_count);
|
|
clk_disable(clks->tahoe_clk);
|
|
clock_gate_count = 0;
|
|
}
|
|
clk_unprepare(clks->tahoe_clk);
|
|
if (clks->sys_tahoe != NULL) {
|
|
clk_disable_unprepare(clks->sys_tahoe);
|
|
}
|
|
/* the power off */
|
|
pm_runtime_put_sync(&tahoe_pdev->dev);
|
|
mdelay(5);
|
|
enc_pr(LOG_INFO, "tahoe power stauts after poweroff: %d\n", pm_runtime_active(&tahoe_pdev->dev));
|
|
}
|
|
|
|
static s32 tahoe_probe(struct platform_device *pdev)
|
|
{
|
|
s32 err = 0, irq, reg_count;
|
|
struct resource res;
|
|
struct device_node *np, *child;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe_probe\n");
|
|
|
|
s_tahoe_major = 0;
|
|
use_reserve = false;
|
|
s_tahoe_irq = -1;
|
|
s_tahoe_irq_requested = false;
|
|
spin_lock(&s_vpu_lock);
|
|
s_tahoe_open_ref_count = 0;
|
|
spin_unlock(&s_vpu_lock);
|
|
|
|
tahoe_dev = NULL;
|
|
tahoe_pdev = NULL;
|
|
s_register_flag = 0;
|
|
|
|
memset(s_video_memory, 0, sizeof(struct venc_drv_common_buffer_t));
|
|
memset(&s_tahoe_register, 0, sizeof(struct venc_drv_buffer_t));
|
|
memset(&s_bit_firmware_info, 0, sizeof(s_bit_firmware_info));
|
|
memset(&res, 0, sizeof(struct resource));
|
|
|
|
cma_cfg_size = 36*SZ_1M; //__need_modify__
|
|
|
|
s_tahoe_register.phys_addr = TAHOE_REG_BASE_ADDR;
|
|
s_tahoe_register.virt_addr = (unsigned long)ioremap(s_tahoe_register.phys_addr, TAHOE_REG_SIZE);
|
|
s_tahoe_register.size = TAHOE_REG_SIZE;
|
|
|
|
enc_pr(LOG_ERROR, "s_venc_register.phys_addr = 0x%lx\n", s_tahoe_register.phys_addr);
|
|
enc_pr(LOG_ERROR, "s_venc_register.virt_addr = 0x%lx, size = 0x%x\n", s_tahoe_register.virt_addr, TAHOE_REG_SIZE);
|
|
|
|
/* get interrupt resource */
|
|
irq = platform_get_irq_byname(pdev, "tahoe_irq0");
|
|
|
|
if (irq < 0) {
|
|
enc_pr(LOG_ERROR, "get tahoe irq resource error\n");
|
|
err = -EFAULT;
|
|
|
|
goto ERROR_PROVE_DEVICE;
|
|
}
|
|
|
|
s_tahoe_irq = irq;
|
|
enc_pr(LOG_DEBUG, "tahoe -irq: %d\n", s_tahoe_irq);
|
|
|
|
/* get vpu clks */
|
|
if (tahoe_clk_get(&pdev->dev, &s_tahoe_clks)) {
|
|
enc_pr(LOG_DEBUG, "get tahoe clks fail.\n");
|
|
goto ERROR_PROVE_DEVICE;
|
|
} else
|
|
enc_pr(LOG_DEBUG, "tahoe. clock get success\n");
|
|
|
|
reg_count = 0;
|
|
np = pdev->dev.of_node;
|
|
|
|
for_each_child_of_node(np, child) {
|
|
if (of_address_to_resource(child, 0, &res) || (reg_count > 1)) {
|
|
enc_pr(LOG_ERROR, "no reg ranges or more reg ranges %d\n", reg_count);
|
|
err = -ENXIO;
|
|
goto ERROR_PROVE_DEVICE;
|
|
}
|
|
|
|
/* if platform driver is implemented */
|
|
if (res.start != 0) {
|
|
s_tahoe_register.phys_addr = res.start;
|
|
s_tahoe_register.virt_addr = (ulong)ioremap(res.start, resource_size(&res));
|
|
s_tahoe_register.size = res.end - res.start;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe base address get from platform driver ");
|
|
enc_pr(LOG_DEBUG, "physical addr=0x%lx, virtual addr=0x%lx\n",
|
|
s_tahoe_register.phys_addr, s_tahoe_register.virt_addr);
|
|
} else {
|
|
s_tahoe_register.phys_addr = TAHOE_REG_BASE_ADDR;
|
|
s_tahoe_register.virt_addr = (ulong)ioremap(s_tahoe_register.phys_addr, TAHOE_REG_SIZE);
|
|
s_tahoe_register.size = TAHOE_REG_SIZE;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe base address get from defined value ");
|
|
enc_pr(LOG_DEBUG, "physical addr=0x%lx, virtual addr=0x%lx\n",
|
|
s_tahoe_register.phys_addr, s_tahoe_register.virt_addr);
|
|
}
|
|
reg_count++;
|
|
}
|
|
|
|
/* reset: tahoe_core_rst/tahoe_a_rst/tahoe_apb_rst/tahoe_sys_rst */
|
|
if (tahoe_rst_get(&pdev->dev, &s_tahoe_rsts)) {
|
|
enc_pr(LOG_DEBUG, "get tahoe rsts fail.\n");
|
|
goto ERROR_PROVE_DEVICE;
|
|
} else
|
|
enc_pr(LOG_DEBUG, "tahoe. rsts get success\n");
|
|
|
|
/* get the major number of the character device */
|
|
if (init_tahoe_device()) {
|
|
err = -EBUSY;
|
|
enc_pr(LOG_ERROR, "could not allocate major number\n");
|
|
|
|
goto ERROR_PROVE_DEVICE;
|
|
}
|
|
|
|
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
|
|
|
|
enc_pr(LOG_INFO, "SUCCESS alloc_chrdev_region\n");
|
|
|
|
tasklet_init(&tahoe_tasklet, tahoe_isr_tasklet, (ulong)&s_tahoe_drv_context);
|
|
tahoe_pdev = pdev;
|
|
pm_runtime_enable(&tahoe_pdev->dev);
|
|
return 0;
|
|
|
|
ERROR_PROVE_DEVICE:
|
|
if (s_tahoe_register.virt_addr) {
|
|
iounmap((void *)s_tahoe_register.virt_addr);
|
|
memset(&s_tahoe_register, 0, sizeof(struct venc_drv_buffer_t));
|
|
}
|
|
|
|
uninit_tahoe_device();
|
|
return err;
|
|
}
|
|
|
|
static KV_INT_TO_VOID tahoe_remove(struct platform_device *pdev)
|
|
{
|
|
int i;
|
|
enc_pr(LOG_DEBUG, "tahoe_remove\n");
|
|
|
|
for (i = 0; i < MAX_INSTANCE; i++) {
|
|
if (s_video_memory[i].phys_addr) {
|
|
codec_mm_free_for_dma(
|
|
DEVICE_NAME,
|
|
s_video_memory[i].phys_addr);
|
|
memset(&s_video_memory[i],
|
|
0, sizeof(struct venc_drv_common_buffer_t));
|
|
}
|
|
}
|
|
|
|
if (s_tahoe_irq_requested == true) {
|
|
if (s_tahoe_irq >= 0) {
|
|
free_irq(s_tahoe_irq, &s_tahoe_drv_context);
|
|
s_tahoe_irq = -1;
|
|
}
|
|
s_tahoe_irq_requested = false;
|
|
}
|
|
|
|
if (s_tahoe_register.virt_addr) {
|
|
iounmap((void *)s_tahoe_register.virt_addr);
|
|
memset(&s_tahoe_register,
|
|
0, sizeof(struct venc_drv_buffer_t));
|
|
}
|
|
if (clock_gate_count > 0)
|
|
{
|
|
tahoe_clk_disable(&s_tahoe_clks);
|
|
}
|
|
tahoe_clk_put(&tahoe_pdev->dev, &s_tahoe_clks);
|
|
tahoe_pdev = NULL;
|
|
uninit_tahoe_device();
|
|
return KV_RET_x_TO_VOID(0);
|
|
}
|
|
|
|
static const struct of_device_id tahoe_dt_match[] = {
|
|
{
|
|
.compatible = "amlogic, tahoe",
|
|
},
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver tahoe_driver = {
|
|
.driver = {
|
|
.name = DRIVER_NAME,
|
|
.of_match_table = tahoe_dt_match,
|
|
},
|
|
.probe = tahoe_probe,
|
|
.remove = tahoe_remove,
|
|
};
|
|
|
|
static s32 __init tahoe_init(void)
|
|
{
|
|
s32 res;
|
|
|
|
enc_pr(LOG_DEBUG, "tahoe_init\n");
|
|
res = platform_driver_register(&tahoe_driver);
|
|
enc_pr(LOG_DEBUG, "tahoe_init result = 0x%x\n", res);
|
|
return res;
|
|
}
|
|
|
|
static void __exit tahoe_exit(void)
|
|
{
|
|
enc_pr(LOG_DEBUG, "tahoe_exit\n");
|
|
platform_driver_unregister(&tahoe_driver);
|
|
}
|
|
|
|
module_param(print_level, uint, 0664);
|
|
MODULE_PARM_DESC(print_level, "\n print_level\n");
|
|
|
|
module_param(clock_a, uint, 0664);
|
|
MODULE_PARM_DESC(clock_a, "\n clock_a\n");
|
|
|
|
MODULE_AUTHOR("Amlogic Inc.");
|
|
MODULE_DESCRIPTION("Tahoe linux driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(tahoe_init);
|
|
module_exit(tahoe_exit);
|