video: rockchip: vcodec: add vpu codec drivers
authorsayon.chen <sayon.chen@rock-chips.com>
Tue, 8 Mar 2016 10:02:32 +0000 (18:02 +0800)
committerGerrit Code Review <gerrit@rock-chips.com>
Thu, 10 Mar 2016 02:26:04 +0000 (10:26 +0800)
move vpu codec code to drivers/video/rockchip

Change-Id: Idf4100181200cf28a18990da7088bee495f10fcb
Signed-off-by: sayon.chen <sayon.chen@rock-chips.com>
12 files changed:
arch/arm/mach-rockchip/vcodec_service.c [deleted file]
arch/arm/mach-rockchip/vcodec_service.h [deleted file]
drivers/video/rockchip/Kconfig
drivers/video/rockchip/Makefile
drivers/video/rockchip/vcodec/Kconfig [new file with mode: 0644]
drivers/video/rockchip/vcodec/Makefile [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_hw_info.h [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_hw_rkv.h [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_hw_vpu.h [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_hw_vpu2.h [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_service.c [new file with mode: 0644]
drivers/video/rockchip/vcodec/vcodec_service.h [new file with mode: 0644]

diff --git a/arch/arm/mach-rockchip/vcodec_service.c b/arch/arm/mach-rockchip/vcodec_service.c
deleted file mode 100755 (executable)
index c28f44d..0000000
+++ /dev/null
@@ -1,3153 +0,0 @@
-/**
- * Copyright (C) 2014 ROCKCHIP, Inc.
- * author: chenhengming chm@rock-chips.com
- *        Alpha Lin, alpha.lin@rock-chips.com
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/clk.h>
-#include <linux/compat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/ioport.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/platform_device.h>
-#include <linux/reset.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/wakelock.h>
-#include <linux/cdev.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/rockchip/cpu.h>
-#include <linux/rockchip/cru.h>
-#include <linux/rockchip/pmu.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-
-#include <asm/cacheflush.h>
-#include <linux/uaccess.h>
-#include <linux/rockchip/grf.h>
-
-#if defined(CONFIG_ION_ROCKCHIP)
-#include <linux/rockchip_ion.h>
-#endif
-
-#if defined(CONFIG_ROCKCHIP_IOMMU) & defined(CONFIG_ION_ROCKCHIP)
-#define CONFIG_VCODEC_MMU
-#endif
-
-#ifdef CONFIG_VCODEC_MMU
-#include <linux/rockchip-iovmm.h>
-#include <linux/dma-buf.h>
-#endif
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#endif
-
-#if defined(CONFIG_ARCH_RK319X)
-#include <mach/grf.h>
-#endif
-
-#include "vcodec_service.h"
-
-/*
- * debug flag usage:
- * +------+-------------------+
- * | 8bit |      24bit        |
- * +------+-------------------+
- *  0~23 bit is for different information type
- * 24~31 bit is for information print format
- */
-
-#define DEBUG_POWER                            0x00000001
-#define DEBUG_CLOCK                            0x00000002
-#define DEBUG_IRQ_STATUS                       0x00000004
-#define DEBUG_IOMMU                            0x00000008
-#define DEBUG_IOCTL                            0x00000010
-#define DEBUG_FUNCTION                         0x00000020
-#define DEBUG_REGISTER                         0x00000040
-#define DEBUG_EXTRA_INFO                       0x00000080
-#define DEBUG_TIMING                           0x00000100
-
-#define PRINT_FUNCTION                         0x80000000
-#define PRINT_LINE                             0x40000000
-
-static int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug,
-                "Debug level - higher value produces more verbose messages");
-
-#define HEVC_TEST_ENABLE       0
-#define VCODEC_CLOCK_ENABLE    1
-
-typedef enum {
-       VPU_DEC_ID_9190         = 0x6731,
-       VPU_ID_8270             = 0x8270,
-       VPU_ID_4831             = 0x4831,
-       HEVC_ID                 = 0x6867,
-} VPU_HW_ID;
-
-enum VPU_HW_SPEC {
-       VPU_TYPE_VPU,
-       VPU_TYPE_HEVC,
-       VPU_TYPE_COMBO_NOENC,
-       VPU_TYPE_COMBO
-};
-
-typedef enum {
-       VPU_DEC_TYPE_9190       = 0,
-       VPU_ENC_TYPE_8270       = 0x100,
-       VPU_ENC_TYPE_4831       ,
-} VPU_HW_TYPE_E;
-
-typedef enum VPU_FREQ {
-       VPU_FREQ_200M,
-       VPU_FREQ_266M,
-       VPU_FREQ_300M,
-       VPU_FREQ_400M,
-       VPU_FREQ_500M,
-       VPU_FREQ_600M,
-       VPU_FREQ_DEFAULT,
-       VPU_FREQ_BUT,
-} VPU_FREQ;
-
-typedef struct {
-       VPU_HW_ID               hw_id;
-       unsigned long           hw_addr;
-       unsigned long           enc_offset;
-       unsigned long           enc_reg_num;
-       unsigned long           enc_io_size;
-       unsigned long           dec_offset;
-       unsigned long           dec_reg_num;
-       unsigned long           dec_io_size;
-} VPU_HW_INFO_E;
-
-struct extra_info_elem {
-       u32 index;
-       u32 offset;
-};
-
-#define EXTRA_INFO_MAGIC       0x4C4A46
-
-struct extra_info_for_iommu {
-       u32 magic;
-       u32 cnt;
-       struct extra_info_elem elem[20];
-};
-
-#define MHZ                                    (1000*1000)
-
-#define REG_NUM_9190_DEC                       (60)
-#define REG_NUM_9190_PP                                (41)
-#define REG_NUM_9190_DEC_PP                    (REG_NUM_9190_DEC+REG_NUM_9190_PP)
-
-#define REG_NUM_DEC_PP                         (REG_NUM_9190_DEC+REG_NUM_9190_PP)
-
-#define REG_NUM_ENC_8270                       (96)
-#define REG_SIZE_ENC_8270                      (0x200)
-#define REG_NUM_ENC_4831                       (164)
-#define REG_SIZE_ENC_4831                      (0x400)
-
-#define REG_NUM_HEVC_DEC                       (68)
-
-#define SIZE_REG(reg)                          ((reg)*4)
-
-static VPU_HW_INFO_E vpu_hw_set[] = {
-       [0] = {
-               .hw_id          = VPU_ID_8270,
-               .hw_addr        = 0,
-               .enc_offset     = 0x0,
-               .enc_reg_num    = REG_NUM_ENC_8270,
-               .enc_io_size    = REG_NUM_ENC_8270 * 4,
-               .dec_offset     = REG_SIZE_ENC_8270,
-               .dec_reg_num    = REG_NUM_9190_DEC_PP,
-               .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
-       },
-       [1] = {
-               .hw_id          = VPU_ID_4831,
-               .hw_addr        = 0,
-               .enc_offset     = 0x0,
-               .enc_reg_num    = REG_NUM_ENC_4831,
-               .enc_io_size    = REG_NUM_ENC_4831 * 4,
-               .dec_offset     = REG_SIZE_ENC_4831,
-               .dec_reg_num    = REG_NUM_9190_DEC_PP,
-               .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
-       },
-       [2] = {
-               .hw_id          = HEVC_ID,
-               .hw_addr        = 0,
-               .dec_offset     = 0x0,
-               .dec_reg_num    = REG_NUM_HEVC_DEC,
-               .dec_io_size    = REG_NUM_HEVC_DEC * 4,
-       },
-       [3] = {
-               .hw_id          = VPU_DEC_ID_9190,
-               .hw_addr        = 0,
-               .enc_offset     = 0x0,
-               .enc_reg_num    = 0,
-               .enc_io_size    = 0,
-               .dec_offset     = 0,
-               .dec_reg_num    = REG_NUM_9190_DEC_PP,
-               .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
-       },
-};
-
-#ifndef BIT
-#define BIT(x)                                 (1<<(x))
-#endif
-
-// interrupt and error status register
-#define DEC_INTERRUPT_REGISTER                 1
-#define DEC_INTERRUPT_BIT                      BIT(8)
-#define DEC_READY_BIT                          BIT(12)
-#define DEC_BUS_ERROR_BIT                      BIT(13)
-#define DEC_BUFFER_EMPTY_BIT                   BIT(14)
-#define DEC_ASO_ERROR_BIT                      BIT(15)
-#define DEC_STREAM_ERROR_BIT                   BIT(16)
-#define DEC_SLICE_DONE_BIT                     BIT(17)
-#define DEC_TIMEOUT_BIT                                BIT(18)
-#define DEC_ERR_MASK                           DEC_BUS_ERROR_BIT \
-                                               |DEC_BUFFER_EMPTY_BIT \
-                                               |DEC_STREAM_ERROR_BIT \
-                                               |DEC_TIMEOUT_BIT
-
-#define PP_INTERRUPT_REGISTER                  60
-#define PP_INTERRUPT_BIT                       BIT(8)
-#define PP_READY_BIT                           BIT(12)
-#define PP_BUS_ERROR_BIT                       BIT(13)
-#define PP_ERR_MASK                            PP_BUS_ERROR_BIT
-
-#define ENC_INTERRUPT_REGISTER                 1
-#define ENC_INTERRUPT_BIT                      BIT(0)
-#define ENC_READY_BIT                          BIT(2)
-#define ENC_BUS_ERROR_BIT                      BIT(3)
-#define ENC_BUFFER_FULL_BIT                    BIT(5)
-#define ENC_TIMEOUT_BIT                                BIT(6)
-#define ENC_ERR_MASK                           ENC_BUS_ERROR_BIT \
-                                               |ENC_BUFFER_FULL_BIT \
-                                               |ENC_TIMEOUT_BIT
-
-#define HEVC_INTERRUPT_REGISTER                        1
-#define HEVC_DEC_INT_RAW_BIT                   BIT(9)
-#define HEVC_DEC_BUS_ERROR_BIT                 BIT(13)
-#define HEVC_DEC_STR_ERROR_BIT                 BIT(14)
-#define HEVC_DEC_TIMEOUT_BIT                   BIT(15)
-#define HEVC_DEC_BUFFER_EMPTY_BIT              BIT(16)
-#define HEVC_DEC_COLMV_ERROR_BIT               BIT(17)
-#define HEVC_DEC_ERR_MASK                      HEVC_DEC_BUS_ERROR_BIT \
-                                               |HEVC_DEC_STR_ERROR_BIT \
-                                               |HEVC_DEC_TIMEOUT_BIT \
-                                               |HEVC_DEC_BUFFER_EMPTY_BIT \
-                                               |HEVC_DEC_COLMV_ERROR_BIT
-
-
-// gating configuration set
-#define VPU_REG_EN_ENC                         14
-#define VPU_REG_ENC_GATE                       2
-#define VPU_REG_ENC_GATE_BIT                   (1<<4)
-
-#define VPU_REG_EN_DEC                         1
-#define VPU_REG_DEC_GATE                       2
-#define VPU_REG_DEC_GATE_BIT                   (1<<10)
-#define VPU_REG_EN_PP                          0
-#define VPU_REG_PP_GATE                        1
-#define VPU_REG_PP_GATE_BIT                    (1<<8)
-#define VPU_REG_EN_DEC_PP                      1
-#define VPU_REG_DEC_PP_GATE                    61
-#define VPU_REG_DEC_PP_GATE_BIT                (1<<8)
-
-#define DEBUG
-#ifdef DEBUG
-#define vpu_debug_func(type, fmt, args...)                     \
-       do {                                                    \
-               if (unlikely(debug & type)) {                   \
-                       pr_info("%s:%d: " fmt,                  \
-                                __func__, __LINE__, ##args);   \
-               }                                               \
-       } while (0)
-#define vpu_debug(type, fmt, args...)                          \
-       do {                                                    \
-               if (unlikely(debug & type)) {                   \
-                       pr_info(fmt, ##args);                   \
-               }                                               \
-       } while (0)
-#else
-#define vpu_debug_func(level, fmt, args...)
-#define vpu_debug(level, fmt, args...)
-#endif
-
-#define vpu_debug_enter() vpu_debug_func(DEBUG_FUNCTION, "enter\n")
-#define vpu_debug_leave() vpu_debug_func(DEBUG_FUNCTION, "leave\n")
-
-#define vpu_err(fmt, args...)                          \
-               pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
-
-#if defined(CONFIG_VCODEC_MMU)
-static u8 addr_tbl_vpu_h264dec[] = {
-       12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
-       25, 26, 27, 28, 29, 40, 41
-};
-
-static u8 addr_tbl_vpu_vp8dec[] = {
-       10, 12, 13, 14, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 40
-};
-
-static u8 addr_tbl_vpu_vp6dec[] = {
-       12, 13, 14, 18, 27, 40
-};
-
-static u8 addr_tbl_vpu_vc1dec[] = {
-       12, 13, 14, 15, 16, 17, 27, 41
-};
-
-static u8 addr_tbl_vpu_jpegdec[] = {
-       12, 40, 66, 67
-};
-
-static u8 addr_tbl_vpu_defaultdec[] = {
-       12, 13, 14, 15, 16, 17, 40, 41
-};
-
-static u8 addr_tbl_vpu_enc[] = {
-       5, 6, 7, 8, 9, 10, 11, 12, 13, 51
-};
-
-static u8 addr_tbl_hevc_dec[] = {
-       4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-       21, 22, 23, 24, 42, 43
-};
-#endif
-
-enum VPU_DEC_FMT {
-       VPU_DEC_FMT_H264,
-       VPU_DEC_FMT_MPEG4,
-       VPU_DEC_FMT_H263,
-       VPU_DEC_FMT_JPEG,
-       VPU_DEC_FMT_VC1,
-       VPU_DEC_FMT_MPEG2,
-       VPU_DEC_FMT_MPEG1,
-       VPU_DEC_FMT_VP6,
-       VPU_DEC_FMT_RV,
-       VPU_DEC_FMT_VP7,
-       VPU_DEC_FMT_VP8,
-       VPU_DEC_FMT_AVS,
-       VPU_DEC_FMT_SVC,
-       VPU_DEC_FMT_VC2,
-       VPU_DEC_FMT_MVC,
-       VPU_DEC_FMT_THEORA,
-       VPU_DEC_FMT_RES
-};
-
-/**
- * struct for process session which connect to vpu
- *
- * @author ChenHengming (2011-5-3)
- */
-typedef struct vpu_session {
-       enum VPU_CLIENT_TYPE type;
-       /* a linked list of data so we can access them for debugging */
-       struct list_head list_session;
-       /* a linked list of register data waiting for process */
-       struct list_head waiting;
-       /* a linked list of register data in processing */
-       struct list_head running;
-       /* a linked list of register data processed */
-       struct list_head done;
-       wait_queue_head_t wait;
-       pid_t pid;
-       atomic_t task_running;
-} vpu_session;
-
-/**
- * struct for process register set
- *
- * @author ChenHengming (2011-5-4)
- */
-typedef struct vpu_reg {
-       enum VPU_CLIENT_TYPE type;
-       VPU_FREQ freq;
-       vpu_session *session;
-       struct vpu_subdev_data *data;
-       struct list_head session_link;          /* link to vpu service session */
-       struct list_head status_link;           /* link to register set list */
-       unsigned long size;
-#if defined(CONFIG_VCODEC_MMU)
-       struct list_head mem_region_list;
-       u32 dec_base;
-#endif
-       u32 *reg;
-} vpu_reg;
-
-typedef struct vpu_device {
-       atomic_t                irq_count_codec;
-       atomic_t                irq_count_pp;
-       unsigned long           iobaseaddr;
-       unsigned int            iosize;
-       volatile u32            *hwregs;
-} vpu_device;
-
-enum vcodec_device_id {
-       VCODEC_DEVICE_ID_VPU,
-       VCODEC_DEVICE_ID_HEVC,
-       VCODEC_DEVICE_ID_COMBO
-};
-
-enum VCODEC_RUNNING_MODE {
-       VCODEC_RUNNING_MODE_NONE = -1,
-       VCODEC_RUNNING_MODE_VPU,
-       VCODEC_RUNNING_MODE_HEVC,
-};
-
-struct vcodec_mem_region {
-       struct list_head srv_lnk;
-       struct list_head reg_lnk;
-       struct list_head session_lnk;
-       unsigned long iova;     /* virtual address for iommu */
-       unsigned long len;
-       u32 reg_idx;
-       struct ion_handle *hdl;
-};
-
-enum vpu_ctx_state {
-       MMU_ACTIVATED   = BIT(0)
-};
-
-struct vpu_subdev_data {
-       struct cdev cdev;
-       dev_t dev_t;
-       struct class *cls;
-       struct device *child_dev;
-
-       int irq_enc;
-       int irq_dec;
-       struct vpu_service_info *pservice;
-
-       u32 *regs;
-       enum VCODEC_RUNNING_MODE mode;
-       struct list_head lnk_service;
-
-       struct device *dev;
-
-       vpu_device enc_dev;
-       vpu_device dec_dev;
-       VPU_HW_INFO_E *hw_info;
-
-       u32 reg_size;
-       unsigned long state;
-
-#ifdef CONFIG_DEBUG_FS
-       struct dentry *debugfs_dir;
-       struct dentry *debugfs_file_regs;
-#endif
-
-#if defined(CONFIG_VCODEC_MMU)
-       struct device *mmu_dev;
-#endif
-};
-
-typedef struct vpu_service_info {
-       struct wake_lock wake_lock;
-       struct delayed_work power_off_work;
-       struct mutex lock;
-       struct list_head waiting;               /* link to link_reg in struct vpu_reg */
-       struct list_head running;               /* link to link_reg in struct vpu_reg */
-       struct list_head done;                  /* link to link_reg in struct vpu_reg */
-       struct list_head session;               /* link to list_session in struct vpu_session */
-       atomic_t total_running;
-       atomic_t enabled;
-       atomic_t power_on_cnt;
-       atomic_t power_off_cnt;
-       vpu_reg *reg_codec;
-       vpu_reg *reg_pproc;
-       vpu_reg *reg_resev;
-       struct vpu_dec_config dec_config;
-       struct vpu_enc_config enc_config;
-
-       bool auto_freq;
-       bool bug_dec_addr;
-       atomic_t freq_status;
-
-       struct clk *aclk_vcodec;
-       struct clk *hclk_vcodec;
-       struct clk *clk_core;
-       struct clk *clk_cabac;
-       struct clk *pd_video;
-
-#ifdef CONFIG_RESET_CONTROLLER
-       struct reset_control *rst_a;
-       struct reset_control *rst_h;
-       struct reset_control *rst_v;
-#endif
-       struct device *dev;
-
-       u32 irq_status;
-       atomic_t reset_request;
-#if defined(CONFIG_VCODEC_MMU)
-       struct ion_client *ion_client;
-       struct list_head mem_region_list;
-#endif
-
-       enum vcodec_device_id dev_id;
-
-       enum VCODEC_RUNNING_MODE curr_mode;
-       u32 prev_mode;
-
-       struct delayed_work simulate_work;
-
-       u32 mode_bit;
-       u32 mode_ctrl;
-       u32 *reg_base;
-       u32 ioaddr;
-       struct regmap *grf;
-       u32 *grf_base;
-
-       char *name;
-
-       u32 subcnt;
-       struct list_head subdev_list;
-} vpu_service_info;
-
-struct vcodec_combo {
-       struct vpu_service_info *vpu_srv;
-       struct vpu_service_info *hevc_srv;
-       struct list_head waiting;
-       struct list_head running;
-       struct mutex run_lock;
-       vpu_reg *reg_codec;
-       enum vcodec_device_id current_hw_mode;
-};
-
-struct vpu_request {
-       u32 *req;
-       u32 size;
-};
-
-#ifdef CONFIG_COMPAT
-struct compat_vpu_request {
-       compat_uptr_t req;
-       u32 size;
-};
-#endif
-
-/* debugfs root directory for all device (vpu, hevc).*/
-static struct dentry *parent;
-
-#ifdef CONFIG_DEBUG_FS
-static int vcodec_debugfs_init(void);
-static void vcodec_debugfs_exit(void);
-static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent);
-static int debug_vcodec_open(struct inode *inode, struct file *file);
-
-static const struct file_operations debug_vcodec_fops = {
-       .open = debug_vcodec_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-#endif
-
-#define VDPU_SOFT_RESET_REG    101
-#define VDPU_CLEAN_CACHE_REG   516
-#define VEPU_CLEAN_CACHE_REG   772
-#define HEVC_CLEAN_CACHE_REG   260
-
-#define VPU_REG_ENABLE(base, reg)      do { \
-                                               base[reg] = 1; \
-                                       } while (0)
-
-#define VDPU_SOFT_RESET(base)  VPU_REG_ENABLE(base, VDPU_SOFT_RESET_REG)
-#define VDPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VDPU_CLEAN_CACHE_REG)
-#define VEPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VEPU_CLEAN_CACHE_REG)
-#define HEVC_CLEAN_CACHE(base) VPU_REG_ENABLE(base, HEVC_CLEAN_CACHE_REG)
-
-#define VPU_POWER_OFF_DELAY            4*HZ /* 4s */
-#define VPU_TIMEOUT_DELAY              2*HZ /* 2s */
-
-typedef struct {
-       char *name;
-       struct timeval start;
-       struct timeval end;
-       u32 error_mask;
-} task_info;
-
-typedef enum {
-       TASK_VPU_ENC,
-       TASK_VPU_DEC,
-       TASK_VPU_PP,
-       TASK_RKDEC_HEVC,
-       TASK_TYPE_BUTT,
-} TASK_TYPE;
-
-task_info tasks[TASK_TYPE_BUTT] = {
-       {
-               .name = "enc",
-               .error_mask = ENC_ERR_MASK
-       },
-       {
-               .name = "dec",
-               .error_mask = DEC_ERR_MASK
-       },
-       {
-               .name = "pp",
-               .error_mask = PP_ERR_MASK
-       },
-       {
-               .name = "hevc",
-               .error_mask = HEVC_DEC_ERR_MASK
-       },
-};
-
-static void time_record(task_info *task, int is_end)
-{
-       if (unlikely(debug & DEBUG_TIMING)) {
-               do_gettimeofday((is_end)?(&task->end):(&task->start));
-       }
-}
-
-static void time_diff(task_info *task)
-{
-       vpu_debug(DEBUG_TIMING, "%s task: %ld ms\n", task->name,
-                       (task->end.tv_sec  - task->start.tv_sec)  * 1000 +
-                       (task->end.tv_usec - task->start.tv_usec) / 1000);
-}
-
-static void vcodec_enter_mode(struct vpu_subdev_data *data)
-{
-       int bits;
-       u32 raw = 0;
-       struct vpu_service_info *pservice = data->pservice;
-       struct vpu_subdev_data *subdata, *n;
-       if (pservice->subcnt < 2) {
-#if defined(CONFIG_VCODEC_MMU)
-               if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
-                       set_bit(MMU_ACTIVATED, &data->state);
-                       if (atomic_read(&pservice->enabled))
-                               rockchip_iovmm_activate(data->dev);
-                       else
-                               BUG_ON(!atomic_read(&pservice->enabled));
-               }
-#endif
-               return;
-       }
-
-       if (pservice->curr_mode == data->mode)
-               return;
-
-       vpu_debug(DEBUG_IOMMU, "vcodec enter mode %d\n", data->mode);
-#if defined(CONFIG_VCODEC_MMU)
-       list_for_each_entry_safe(subdata, n, &pservice->subdev_list, lnk_service) {
-               if (data != subdata && subdata->mmu_dev &&
-                   test_bit(MMU_ACTIVATED, &subdata->state)) {
-                       clear_bit(MMU_ACTIVATED, &subdata->state);
-                       rockchip_iovmm_deactivate(subdata->dev);
-               }
-       }
-#endif
-       bits = 1 << pservice->mode_bit;
-#ifdef CONFIG_MFD_SYSCON
-       if (pservice->grf) {
-               regmap_read(pservice->grf, pservice->mode_ctrl, &raw);
-
-               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
-                       regmap_write(pservice->grf, pservice->mode_ctrl,
-                               raw | bits | (bits << 16));
-               else
-                       regmap_write(pservice->grf, pservice->mode_ctrl,
-                               (raw & (~bits)) | (bits << 16));
-       } else if (pservice->grf_base) {
-               raw = readl_relaxed(pservice->grf_base + pservice->mode_ctrl / 4);
-               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
-                       writel_relaxed(raw | bits | (bits << 16),
-                               pservice->grf_base + pservice->mode_ctrl / 4);
-               else
-                       writel_relaxed((raw & (~bits)) | (bits << 16),
-                               pservice->grf_base + pservice->mode_ctrl / 4);
-       } else {
-               vpu_err("no grf resource define, switch decoder failed\n");
-               return;
-       }
-#else
-       if (pervice->grf_base) {
-               raw = readl_relaxed(pservice->grf_base + pservice->mode_ctrl / 4);
-               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
-                       writel_relaxed(raw | bits | (bits << 16),
-                               pservice->grf_base + pservice->mode_ctrl / 4);
-               else
-                       writel_relaxed((raw & (~bits)) | (bits << 16),
-                               pservice->grf_base + pservice->mode_ctrl / 4);
-       } else {
-               vpu_err("no grf resource define, switch decoder failed\n");
-               return;
-       }
-#endif
-#if defined(CONFIG_VCODEC_MMU)
-       if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
-               set_bit(MMU_ACTIVATED, &data->state);
-               if (atomic_read(&pservice->enabled))
-                       rockchip_iovmm_activate(data->dev);
-               else
-                       BUG_ON(!atomic_read(&pservice->enabled));
-       }
-#endif
-       pservice->prev_mode = pservice->curr_mode;
-       pservice->curr_mode = data->mode;
-}
-
-static void vcodec_exit_mode(struct vpu_subdev_data *data)
-{
-       if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
-               clear_bit(MMU_ACTIVATED, &data->state);
-               rockchip_iovmm_deactivate(data->dev);
-               data->pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
-       }
-}
-
-static int vpu_get_clk(struct vpu_service_info *pservice)
-{
-#if VCODEC_CLOCK_ENABLE
-       switch (pservice->dev_id) {
-       case VCODEC_DEVICE_ID_HEVC:
-               pservice->pd_video = devm_clk_get(pservice->dev, "pd_hevc");
-               if (IS_ERR(pservice->pd_video)) {
-                       dev_err(pservice->dev, "failed on clk_get pd_hevc\n");
-                       return -1;
-               }
-       case VCODEC_DEVICE_ID_COMBO:
-               pservice->clk_cabac = devm_clk_get(pservice->dev, "clk_cabac");
-               if (IS_ERR(pservice->clk_cabac)) {
-                       dev_err(pservice->dev, "failed on clk_get clk_cabac\n");
-                       pservice->clk_cabac = NULL;
-               }
-               pservice->clk_core = devm_clk_get(pservice->dev, "clk_core");
-               if (IS_ERR(pservice->clk_core)) {
-                       dev_err(pservice->dev, "failed on clk_get clk_core\n");
-                       return -1;
-               }
-       case VCODEC_DEVICE_ID_VPU:
-               pservice->aclk_vcodec = devm_clk_get(pservice->dev, "aclk_vcodec");
-               if (IS_ERR(pservice->aclk_vcodec)) {
-                       dev_err(pservice->dev, "failed on clk_get aclk_vcodec\n");
-                       return -1;
-               }
-
-               pservice->hclk_vcodec = devm_clk_get(pservice->dev, "hclk_vcodec");
-               if (IS_ERR(pservice->hclk_vcodec)) {
-                       dev_err(pservice->dev, "failed on clk_get hclk_vcodec\n");
-                       return -1;
-               }
-               if (pservice->pd_video == NULL) {
-                       pservice->pd_video = devm_clk_get(pservice->dev, "pd_video");
-                       if (IS_ERR(pservice->pd_video)) {
-                               pservice->pd_video = NULL;
-                               dev_info(pservice->dev, "do not have pd_video\n");
-                       }
-               }
-               break;
-       default:
-               ;
-       }
-
-       return 0;
-#else
-       return 0;
-#endif
-}
-
-static void vpu_put_clk(struct vpu_service_info *pservice)
-{
-#if VCODEC_CLOCK_ENABLE
-       if (pservice->pd_video)
-               devm_clk_put(pservice->dev, pservice->pd_video);
-       if (pservice->aclk_vcodec)
-               devm_clk_put(pservice->dev, pservice->aclk_vcodec);
-       if (pservice->hclk_vcodec)
-               devm_clk_put(pservice->dev, pservice->hclk_vcodec);
-       if (pservice->clk_core)
-               devm_clk_put(pservice->dev, pservice->clk_core);
-       if (pservice->clk_cabac)
-               devm_clk_put(pservice->dev, pservice->clk_cabac);
-#endif
-}
-
-static void vpu_reset(struct vpu_subdev_data *data)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       enum pmu_idle_req type = IDLE_REQ_VIDEO;
-
-       if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC)
-               type = IDLE_REQ_HEVC;
-
-       pr_info("%s: resetting...", dev_name(pservice->dev));
-
-#if defined(CONFIG_ARCH_RK29)
-       clk_disable(aclk_ddr_vepu);
-       cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
-       cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);
-       mdelay(10);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);
-       cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);
-       cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);
-       clk_enable(aclk_ddr_vepu);
-#elif defined(CONFIG_ARCH_RK30)
-       pmu_set_idle_request(IDLE_REQ_VIDEO, true);
-       cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true);
-       cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, true);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AXI, true);
-       mdelay(1);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AXI, false);
-       cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false);
-       cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, false);
-       cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);
-       pmu_set_idle_request(IDLE_REQ_VIDEO, false);
-#else
-#endif
-       WARN_ON(pservice->reg_codec != NULL);
-       WARN_ON(pservice->reg_pproc != NULL);
-       WARN_ON(pservice->reg_resev != NULL);
-       pservice->reg_codec = NULL;
-       pservice->reg_pproc = NULL;
-       pservice->reg_resev = NULL;
-
-       pr_info("for 3288/3368...");
-#ifdef CONFIG_RESET_CONTROLLER
-       if (pservice->rst_a && pservice->rst_h) {
-               if (rockchip_pmu_ops.set_idle_request)
-                       rockchip_pmu_ops.set_idle_request(type, true);
-               pr_info("reset in\n");
-               if (pservice->rst_v)
-                       reset_control_assert(pservice->rst_v);
-               reset_control_assert(pservice->rst_a);
-               reset_control_assert(pservice->rst_h);
-               usleep_range(10, 20);
-               reset_control_deassert(pservice->rst_h);
-               reset_control_deassert(pservice->rst_a);
-               if (pservice->rst_v)
-                       reset_control_deassert(pservice->rst_v);
-               if (rockchip_pmu_ops.set_idle_request)
-                       rockchip_pmu_ops.set_idle_request(type, false);
-       }
-#endif
-
-#if defined(CONFIG_VCODEC_MMU)
-       if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
-               clear_bit(MMU_ACTIVATED, &data->state);
-               if (atomic_read(&pservice->enabled))
-                       rockchip_iovmm_deactivate(data->dev);
-               else
-                       BUG_ON(!atomic_read(&pservice->enabled));
-       }
-#endif
-       atomic_set(&pservice->reset_request, 0);
-       pr_info("done\n");
-}
-
-static void reg_deinit(struct vpu_subdev_data *data, vpu_reg *reg);
-static void vpu_service_session_clear(struct vpu_subdev_data *data, vpu_session *session)
-{
-       vpu_reg *reg, *n;
-       list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
-               reg_deinit(data, reg);
-       }
-       list_for_each_entry_safe(reg, n, &session->running, session_link) {
-               reg_deinit(data, reg);
-       }
-       list_for_each_entry_safe(reg, n, &session->done, session_link) {
-               reg_deinit(data, reg);
-       }
-}
-
-static void vpu_service_dump(struct vpu_service_info *pservice)
-{
-}
-
-static void vpu_service_power_off(struct vpu_service_info *pservice)
-{
-       int total_running;
-       struct vpu_subdev_data *data = NULL, *n;
-       int ret = atomic_add_unless(&pservice->enabled, -1, 0);
-       if (!ret)
-               return;
-
-       total_running = atomic_read(&pservice->total_running);
-       if (total_running) {
-               pr_alert("alert: power off when %d task running!!\n", total_running);
-               mdelay(50);
-               pr_alert("alert: delay 50 ms for running task\n");
-               vpu_service_dump(pservice);
-       }
-
-       pr_info("%s: power off...", dev_name(pservice->dev));
-       udelay(10);
-#if defined(CONFIG_VCODEC_MMU)
-       list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) {
-               if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
-                       clear_bit(MMU_ACTIVATED, &data->state);
-                       rockchip_iovmm_deactivate(data->dev);
-               }
-       }
-       pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
-#endif
-
-#if VCODEC_CLOCK_ENABLE
-       if (pservice->pd_video)
-               clk_disable_unprepare(pservice->pd_video);
-       if (pservice->hclk_vcodec)
-               clk_disable_unprepare(pservice->hclk_vcodec);
-       if (pservice->aclk_vcodec)
-               clk_disable_unprepare(pservice->aclk_vcodec);
-       if (pservice->clk_core)
-               clk_disable_unprepare(pservice->clk_core);
-       if (pservice->clk_cabac)
-               clk_disable_unprepare(pservice->clk_cabac);
-#endif
-
-       atomic_add(1, &pservice->power_off_cnt);
-       wake_unlock(&pservice->wake_lock);
-       pr_info("done\n");
-}
-
-static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice)
-{
-       queue_delayed_work(system_nrt_wq, &pservice->power_off_work, VPU_POWER_OFF_DELAY);
-}
-
-static void vpu_power_off_work(struct work_struct *work_s)
-{
-       struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work);
-       struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, power_off_work);
-
-       if (mutex_trylock(&pservice->lock)) {
-               vpu_service_power_off(pservice);
-               mutex_unlock(&pservice->lock);
-       } else {
-               /* Come back later if the device is busy... */
-               vpu_queue_power_off_work(pservice);
-       }
-}
-
-static void vpu_service_power_on(struct vpu_service_info *pservice)
-{
-       int ret;
-       static ktime_t last;
-       ktime_t now = ktime_get();
-       if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {
-               cancel_delayed_work_sync(&pservice->power_off_work);
-               vpu_queue_power_off_work(pservice);
-               last = now;
-       }
-       ret = atomic_add_unless(&pservice->enabled, 1, 1);
-       if (!ret)
-               return ;
-
-       pr_info("%s: power on\n", dev_name(pservice->dev));
-
-#define BIT_VCODEC_CLK_SEL     (1<<10)
-       if (cpu_is_rk312x())
-               writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1) |
-                       BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16),
-                       RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
-
-#if VCODEC_CLOCK_ENABLE
-       if (pservice->aclk_vcodec)
-               clk_prepare_enable(pservice->aclk_vcodec);
-       if (pservice->hclk_vcodec)
-               clk_prepare_enable(pservice->hclk_vcodec);
-       if (pservice->clk_core)
-               clk_prepare_enable(pservice->clk_core);
-       if (pservice->clk_cabac)
-               clk_prepare_enable(pservice->clk_cabac);
-       if (pservice->pd_video)
-               clk_prepare_enable(pservice->pd_video);
-#endif
-
-       udelay(10);
-       atomic_add(1, &pservice->power_on_cnt);
-       wake_lock(&pservice->wake_lock);
-}
-
-static inline bool reg_check_rmvb_wmv(vpu_reg *reg)
-{
-       u32 type = (reg->reg[3] & 0xF0000000) >> 28;
-       return ((type == 8) || (type == 4));
-}
-
-static inline bool reg_check_interlace(vpu_reg *reg)
-{
-       u32 type = (reg->reg[3] & (1 << 23));
-       return (type > 0);
-}
-
-static inline enum VPU_DEC_FMT reg_check_fmt(vpu_reg *reg)
-{
-       enum VPU_DEC_FMT type = (enum VPU_DEC_FMT)((reg->reg[3] & 0xF0000000) >> 28);
-       return type;
-}
-
-static inline int reg_probe_width(vpu_reg *reg)
-{
-       int width_in_mb = reg->reg[4] >> 23;
-       return width_in_mb * 16;
-}
-
-static inline int reg_probe_hevc_y_stride(vpu_reg *reg)
-{
-       int y_virstride = reg->reg[8];
-       return y_virstride;
-}
-
-#if defined(CONFIG_VCODEC_MMU)
-static int vcodec_fd_to_iova(struct vpu_subdev_data *data, vpu_reg *reg,int fd)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       struct ion_handle *hdl;
-       int ret = 0;
-       struct vcodec_mem_region *mem_region;
-
-       hdl = ion_import_dma_buf(pservice->ion_client, fd);
-       if (IS_ERR(hdl)) {
-               vpu_err("import dma-buf from fd %d failed\n", fd);
-               return PTR_ERR(hdl);
-       }
-       mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL);
-
-       if (mem_region == NULL) {
-               vpu_err("allocate memory for iommu memory region failed\n");
-               ion_free(pservice->ion_client, hdl);
-               return -1;
-       }
-
-       mem_region->hdl = hdl;
-       ret = ion_map_iommu(data->dev, pservice->ion_client,
-               mem_region->hdl, &mem_region->iova, &mem_region->len);
-
-       if (ret < 0) {
-               vpu_err("ion map iommu failed\n");
-               kfree(mem_region);
-               ion_free(pservice->ion_client, hdl);
-               return ret;
-       }
-       INIT_LIST_HEAD(&mem_region->reg_lnk);
-       list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);
-       return mem_region->iova;
-}
-
-static int vcodec_bufid_to_iova(struct vpu_subdev_data *data, u8 *tbl,
-                               int size, vpu_reg *reg,
-                               struct extra_info_for_iommu *ext_inf)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       int i;
-       int usr_fd = 0;
-       int offset = 0;
-
-       if (tbl == NULL || size <= 0) {
-               dev_err(pservice->dev, "input arguments invalidate\n");
-               return -1;
-       }
-
-       for (i = 0; i < size; i++) {
-               usr_fd = reg->reg[tbl[i]] & 0x3FF;
-
-               if (tbl[i] == 41 && data->hw_info->hw_id != HEVC_ID &&
-                   (reg->type == VPU_DEC || reg->type == VPU_DEC_PP))
-                       /* special for vpu dec num 41 regitster */
-                       offset = reg->reg[tbl[i]] >> 10 << 4;
-               else
-                       offset = reg->reg[tbl[i]] >> 10;
-
-               if (usr_fd != 0) {
-                       struct ion_handle *hdl;
-                       int ret = 0;
-                       struct vcodec_mem_region *mem_region;
-
-                       hdl = ion_import_dma_buf(pservice->ion_client, usr_fd);
-                       if (IS_ERR(hdl)) {
-                               dev_err(pservice->dev, "import dma-buf from fd %d failed, reg[%d]\n", usr_fd, tbl[i]);
-                               return PTR_ERR(hdl);
-                       }
-
-                       if (tbl[i] == 42 && data->hw_info->hw_id == HEVC_ID){
-                               int i = 0;
-                               char *pps;
-                               pps = (char *)ion_map_kernel(pservice->ion_client,hdl);
-                               for (i=0; i<64; i++) {
-                                       u32 scaling_offset;
-                                       u32 tmp;
-                                       int scaling_fd= 0;
-                                       scaling_offset = (u32)pps[i*80+74];
-                                       scaling_offset += (u32)pps[i*80+75] << 8;
-                                       scaling_offset += (u32)pps[i*80+76] << 16;
-                                       scaling_offset += (u32)pps[i*80+77] << 24;
-                                       scaling_fd = scaling_offset&0x3ff;
-                                       scaling_offset = scaling_offset >> 10;
-                                       if(scaling_fd > 0) {
-                                               tmp = vcodec_fd_to_iova(data, reg, scaling_fd);
-                                               tmp += scaling_offset;
-                                               pps[i*80+74] = tmp & 0xff;
-                                               pps[i*80+75] = (tmp >> 8) & 0xff;
-                                               pps[i*80+76] = (tmp >> 16) & 0xff;
-                                               pps[i*80+77] = (tmp >> 24) & 0xff;
-                                       }
-                               }
-                       }
-
-                       mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL);
-
-                       if (mem_region == NULL) {
-                               dev_err(pservice->dev, "allocate memory for iommu memory region failed\n");
-                               ion_free(pservice->ion_client, hdl);
-                               return -1;
-                       }
-
-                       mem_region->hdl = hdl;
-                       mem_region->reg_idx = tbl[i];
-                       ret = ion_map_iommu(data->dev,
-                                           pservice->ion_client,
-                                           mem_region->hdl,
-                                           &mem_region->iova,
-                                           &mem_region->len);
-
-                       if (ret < 0) {
-                               dev_err(pservice->dev, "ion map iommu failed\n");
-                               kfree(mem_region);
-                               ion_free(pservice->ion_client, hdl);
-                               return ret;
-                       }
-
-                       /* special for vpu dec num 12: record decoded length
-                          hacking for decoded length
-                          NOTE: not a perfect fix, the fd is not recorded */
-                       if (tbl[i] == 12 && data->hw_info->hw_id != HEVC_ID &&
-                                       (reg->type == VPU_DEC || reg->type == VPU_DEC_PP)) {
-                               reg->dec_base = mem_region->iova + offset;
-                               vpu_debug(DEBUG_REGISTER, "dec_set %08x\n", reg->dec_base);
-                       }
-
-                       reg->reg[tbl[i]] = mem_region->iova + offset;
-                       INIT_LIST_HEAD(&mem_region->reg_lnk);
-                       list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);
-               }
-       }
-
-       if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) {
-               for (i=0; i<ext_inf->cnt; i++) {
-                       vpu_debug(DEBUG_IOMMU, "reg[%d] + offset %d\n",
-                                 ext_inf->elem[i].index,
-                                 ext_inf->elem[i].offset);
-                       reg->reg[ext_inf->elem[i].index] +=
-                               ext_inf->elem[i].offset;
-               }
-       }
-
-       return 0;
-}
-
-static int vcodec_reg_address_translate(struct vpu_subdev_data *data,
-                                       vpu_reg *reg,
-                                       struct extra_info_for_iommu *ext_inf)
-{
-       VPU_HW_ID hw_id;
-       u8 *tbl;
-       int size = 0;
-
-       hw_id = data->hw_info->hw_id;
-
-       if (hw_id == HEVC_ID) {
-               tbl = addr_tbl_hevc_dec;
-               size = sizeof(addr_tbl_hevc_dec);
-       } else {
-               if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
-                       switch (reg_check_fmt(reg)) {
-                       case VPU_DEC_FMT_H264:
-                               {
-                                       tbl = addr_tbl_vpu_h264dec;
-                                       size = sizeof(addr_tbl_vpu_h264dec);
-                                       break;
-                               }
-                       case VPU_DEC_FMT_VP8:
-                       case VPU_DEC_FMT_VP7:
-                               {
-                                       tbl = addr_tbl_vpu_vp8dec;
-                                       size = sizeof(addr_tbl_vpu_vp8dec);
-                                       break;
-                               }
-
-                       case VPU_DEC_FMT_VP6:
-                               {
-                                       tbl = addr_tbl_vpu_vp6dec;
-                                       size = sizeof(addr_tbl_vpu_vp6dec);
-                                       break;
-                               }
-                       case VPU_DEC_FMT_VC1:
-                               {
-                                       tbl = addr_tbl_vpu_vc1dec;
-                                       size = sizeof(addr_tbl_vpu_vc1dec);
-                                       break;
-                               }
-
-                       case VPU_DEC_FMT_JPEG:
-                               {
-                                       tbl = addr_tbl_vpu_jpegdec;
-                                       size = sizeof(addr_tbl_vpu_jpegdec);
-                                       break;
-                               }
-                       default:
-                               tbl = addr_tbl_vpu_defaultdec;
-                               size = sizeof(addr_tbl_vpu_defaultdec);
-                               break;
-                       }
-               } else if (reg->type == VPU_ENC) {
-                       tbl = addr_tbl_vpu_enc;
-                       size = sizeof(addr_tbl_vpu_enc);
-               }
-       }
-
-       if (size != 0) {
-               return vcodec_bufid_to_iova(data, tbl, size, reg, ext_inf);
-       } else {
-               return -1;
-       }
-}
-#endif
-
-static vpu_reg *reg_init(struct vpu_subdev_data *data,
-       vpu_session *session, void __user *src, u32 size)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       int extra_size = 0;
-       struct extra_info_for_iommu extra_info;
-       vpu_reg *reg = kmalloc(sizeof(vpu_reg) + data->reg_size, GFP_KERNEL);
-
-       vpu_debug_enter();
-
-       if (NULL == reg) {
-               vpu_err("error: kmalloc fail in reg_init\n");
-               return NULL;
-       }
-
-       if (size > data->reg_size) {
-               /*printk("warning: vpu reg size %u is larger than hw reg size %u\n",
-                 size, data->reg_size);*/
-               extra_size = size - data->reg_size;
-               size = data->reg_size;
-       }
-       reg->session = session;
-       reg->data = data;
-       reg->type = session->type;
-       reg->size = size;
-       reg->freq = VPU_FREQ_DEFAULT;
-       reg->reg = (u32 *)&reg[1];
-       INIT_LIST_HEAD(&reg->session_link);
-       INIT_LIST_HEAD(&reg->status_link);
-
-#if defined(CONFIG_VCODEC_MMU)
-       if (data->mmu_dev)
-               INIT_LIST_HEAD(&reg->mem_region_list);
-#endif
-
-       if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {
-               vpu_err("error: copy_from_user failed in reg_init\n");
-               kfree(reg);
-               return NULL;
-       }
-
-       if (copy_from_user(&extra_info, (u8 *)src + size, extra_size)) {
-               vpu_err("error: copy_from_user failed in reg_init\n");
-               kfree(reg);
-               return NULL;
-       }
-
-#if defined(CONFIG_VCODEC_MMU)
-       if (data->mmu_dev &&
-           0 > vcodec_reg_address_translate(data, reg, &extra_info)) {
-               vpu_err("error: translate reg address failed\n");
-               kfree(reg);
-               return NULL;
-       }
-#endif
-
-       mutex_lock(&pservice->lock);
-       list_add_tail(&reg->status_link, &pservice->waiting);
-       list_add_tail(&reg->session_link, &session->waiting);
-       mutex_unlock(&pservice->lock);
-
-       if (pservice->auto_freq) {
-               if (!soc_is_rk2928g()) {
-                       if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
-                               if (reg_check_rmvb_wmv(reg)) {
-                                       reg->freq = VPU_FREQ_200M;
-                               } else if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
-                                       if (reg_probe_width(reg) > 3200) {
-                                               /*raise frequency for 4k avc.*/
-                                               reg->freq = VPU_FREQ_600M;
-                                       }
-                               } else {
-                                       if (reg_check_interlace(reg)) {
-                                               reg->freq = VPU_FREQ_400M;
-                                       }
-                               }
-                       }
-                       if (data->hw_info->hw_id == HEVC_ID) {
-                               if (reg_probe_hevc_y_stride(reg) > 60000)
-                                       reg->freq = VPU_FREQ_400M;
-                       }
-                       if (reg->type == VPU_PP) {
-                               reg->freq = VPU_FREQ_400M;
-                       }
-               }
-       }
-       vpu_debug_leave();
-       return reg;
-}
-
-static void reg_deinit(struct vpu_subdev_data *data, vpu_reg *reg)
-{
-       struct vpu_service_info *pservice = data->pservice;
-#if defined(CONFIG_VCODEC_MMU)
-       struct vcodec_mem_region *mem_region = NULL, *n;
-#endif
-
-       list_del_init(&reg->session_link);
-       list_del_init(&reg->status_link);
-       if (reg == pservice->reg_codec)
-               pservice->reg_codec = NULL;
-       if (reg == pservice->reg_pproc)
-               pservice->reg_pproc = NULL;
-
-#if defined(CONFIG_VCODEC_MMU)
-       /* release memory region attach to this registers table. */
-       if (data->mmu_dev) {
-               list_for_each_entry_safe(mem_region, n,
-                       &reg->mem_region_list, reg_lnk) {
-                       /* do not unmap iommu manually,
-                          unmap will proccess when memory release */
-                       /*vcodec_enter_mode(data);
-                       ion_unmap_iommu(data->dev,
-                                       pservice->ion_client,
-                                       mem_region->hdl);
-                       vcodec_exit_mode();*/
-                       ion_free(pservice->ion_client, mem_region->hdl);
-                       list_del_init(&mem_region->reg_lnk);
-                       kfree(mem_region);
-               }
-       }
-#endif
-
-       kfree(reg);
-}
-
-static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg)
-{
-       vpu_debug_enter();
-       list_del_init(&reg->status_link);
-       list_add_tail(&reg->status_link, &pservice->running);
-
-       list_del_init(&reg->session_link);
-       list_add_tail(&reg->session_link, &reg->session->running);
-       vpu_debug_leave();
-}
-
-static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count)
-{
-       int i;
-       u32 *dst = (u32 *)&reg->reg[0];
-       vpu_debug_enter();
-       for (i = 0; i < count; i++)
-               *dst++ = *src++;
-       vpu_debug_leave();
-}
-
-static void reg_from_run_to_done(struct vpu_subdev_data *data,
-       vpu_reg *reg)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       int irq_reg = -1;
-
-       vpu_debug_enter();
-
-       list_del_init(&reg->status_link);
-       list_add_tail(&reg->status_link, &pservice->done);
-
-       list_del_init(&reg->session_link);
-       list_add_tail(&reg->session_link, &reg->session->done);
-
-       /*vcodec_enter_mode(data);*/
-       switch (reg->type) {
-       case VPU_ENC : {
-               pservice->reg_codec = NULL;
-               reg_copy_from_hw(reg, data->enc_dev.hwregs, data->hw_info->enc_reg_num);
-               irq_reg = ENC_INTERRUPT_REGISTER;
-               break;
-       }
-       case VPU_DEC : {
-               int reg_len = REG_NUM_9190_DEC;
-               pservice->reg_codec = NULL;
-               reg_copy_from_hw(reg, data->dec_dev.hwregs, reg_len);
-#if defined(CONFIG_VCODEC_MMU)
-               /* revert hack for decoded length */
-               if (data->hw_info->hw_id != HEVC_ID) {
-                       u32 dec_get = reg->reg[12];
-                       s32 dec_length = dec_get - reg->dec_base;
-                       vpu_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length);
-                       reg->reg[12] = dec_length << 10;
-               }
-#endif
-               irq_reg = DEC_INTERRUPT_REGISTER;
-               break;
-       }
-       case VPU_PP : {
-               pservice->reg_pproc = NULL;
-               reg_copy_from_hw(reg, data->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP);
-               data->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
-               break;
-       }
-       case VPU_DEC_PP : {
-               pservice->reg_codec = NULL;
-               pservice->reg_pproc = NULL;
-               reg_copy_from_hw(reg, data->dec_dev.hwregs, REG_NUM_9190_DEC_PP);
-               data->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
-#if defined(CONFIG_VCODEC_MMU)
-               /* revert hack for decoded length */
-               if (data->hw_info->hw_id != HEVC_ID) {
-                       u32 dec_get = reg->reg[12];
-                       s32 dec_length = dec_get - reg->dec_base;
-                       vpu_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length);
-                       reg->reg[12] = dec_length << 10;
-               }
-#endif
-               break;
-       }
-       default : {
-               vpu_err("error: copy reg from hw with unknown type %d\n", reg->type);
-               break;
-       }
-       }
-       vcodec_exit_mode(data);
-
-       if (irq_reg != -1)
-               reg->reg[irq_reg] = pservice->irq_status;
-
-       atomic_sub(1, &reg->session->task_running);
-       atomic_sub(1, &pservice->total_running);
-       wake_up(&reg->session->wait);
-
-       vpu_debug_leave();
-}
-
-static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg)
-{
-       VPU_FREQ curr = atomic_read(&pservice->freq_status);
-       if (curr == reg->freq)
-               return;
-       atomic_set(&pservice->freq_status, reg->freq);
-       switch (reg->freq) {
-       case VPU_FREQ_200M : {
-               clk_set_rate(pservice->aclk_vcodec, 200*MHZ);
-       } break;
-       case VPU_FREQ_266M : {
-               clk_set_rate(pservice->aclk_vcodec, 266*MHZ);
-       } break;
-       case VPU_FREQ_300M : {
-               clk_set_rate(pservice->aclk_vcodec, 300*MHZ);
-       } break;
-       case VPU_FREQ_400M : {
-               clk_set_rate(pservice->aclk_vcodec, 400*MHZ);
-       } break;
-       case VPU_FREQ_500M : {
-               clk_set_rate(pservice->aclk_vcodec, 500*MHZ);
-       } break;
-       case VPU_FREQ_600M : {
-               clk_set_rate(pservice->aclk_vcodec, 600*MHZ);
-       } break;
-       default : {
-               if (soc_is_rk2928g())
-                       clk_set_rate(pservice->aclk_vcodec, 400*MHZ);
-               else
-                       clk_set_rate(pservice->aclk_vcodec, 300*MHZ);
-       } break;
-       }
-}
-
-static void reg_copy_to_hw(struct vpu_subdev_data *data, vpu_reg *reg)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       int i;
-       u32 *src = (u32 *)&reg->reg[0];
-       vpu_debug_enter();
-
-       atomic_add(1, &pservice->total_running);
-       atomic_add(1, &reg->session->task_running);
-       if (pservice->auto_freq)
-               vpu_service_set_freq(pservice, reg);
-
-       vcodec_enter_mode(data);
-
-       switch (reg->type) {
-       case VPU_ENC : {
-               int enc_count = data->hw_info->enc_reg_num;
-               u32 *dst = (u32 *)data->enc_dev.hwregs;
-
-               pservice->reg_codec = reg;
-
-               dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;
-
-               for (i = 0; i < VPU_REG_EN_ENC; i++)
-                       dst[i] = src[i];
-
-               for (i = VPU_REG_EN_ENC + 1; i < enc_count; i++)
-                       dst[i] = src[i];
-
-               VEPU_CLEAN_CACHE(dst);
-
-               dsb(sy);
-
-               dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;
-               dst[VPU_REG_EN_ENC]   = src[VPU_REG_EN_ENC];
-
-               time_record(&tasks[TASK_VPU_ENC], 0);
-       } break;
-       case VPU_DEC : {
-               u32 *dst = (u32 *)data->dec_dev.hwregs;
-
-               pservice->reg_codec = reg;
-
-               if (data->hw_info->hw_id != HEVC_ID) {
-                       for (i = REG_NUM_9190_DEC - 1; i > VPU_REG_DEC_GATE; i--)
-                               dst[i] = src[i];
-                       VDPU_CLEAN_CACHE(dst);
-               } else {
-                       for (i = REG_NUM_HEVC_DEC - 1; i > VPU_REG_EN_DEC; i--)
-                               dst[i] = src[i];
-                       HEVC_CLEAN_CACHE(dst);
-               }
-
-               dsb(sy);
-
-               if (data->hw_info->hw_id != HEVC_ID) {
-                       dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;
-                       dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC];
-               } else {
-                       dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC];
-               }
-               dsb(sy);
-               dmb(sy);
-
-               time_record(&tasks[TASK_VPU_DEC], 0);
-       } break;
-       case VPU_PP : {
-               u32 *dst = (u32 *)data->dec_dev.hwregs + PP_INTERRUPT_REGISTER;
-               pservice->reg_pproc = reg;
-
-               dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;
-
-               for (i = VPU_REG_PP_GATE + 1; i < REG_NUM_9190_PP; i++)
-                       dst[i] = src[i];
-
-               dsb(sy);
-
-               dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];
-
-               time_record(&tasks[TASK_VPU_PP], 0);
-       } break;
-       case VPU_DEC_PP : {
-               u32 *dst = (u32 *)data->dec_dev.hwregs;
-               pservice->reg_codec = reg;
-               pservice->reg_pproc = reg;
-
-               VDPU_SOFT_RESET(dst);
-               VDPU_CLEAN_CACHE(dst);
-
-               for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_9190_DEC_PP; i++)
-                       dst[i] = src[i];
-
-               dst[VPU_REG_EN_DEC_PP]   = src[VPU_REG_EN_DEC_PP] | 0x2;
-               dsb(sy);
-
-               dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;
-               dst[VPU_REG_DEC_GATE]    = src[VPU_REG_DEC_GATE]    | VPU_REG_DEC_GATE_BIT;
-               dst[VPU_REG_EN_DEC]      = src[VPU_REG_EN_DEC];
-
-               time_record(&tasks[TASK_VPU_DEC], 0);
-       } break;
-       default : {
-               vpu_err("error: unsupport session type %d", reg->type);
-               atomic_sub(1, &pservice->total_running);
-               atomic_sub(1, &reg->session->task_running);
-       } break;
-       }
-
-       /*vcodec_exit_mode(data);*/
-       vpu_debug_leave();
-}
-
-static void try_set_reg(struct vpu_subdev_data *data)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_debug_enter();
-       if (!list_empty(&pservice->waiting)) {
-               int can_set = 0;
-               bool change_able = (NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc);
-               int reset_request = atomic_read(&pservice->reset_request);
-               vpu_reg *reg = list_entry(pservice->waiting.next, vpu_reg, status_link);
-
-               vpu_service_power_on(pservice);
-
-               // first check can_set flag
-               if (change_able || !reset_request) {
-                       switch (reg->type) {
-                       case VPU_ENC : {
-                               if (change_able)
-                                       can_set = 1;
-                       } break;
-                       case VPU_DEC : {
-                               if (NULL == pservice->reg_codec)
-                                       can_set = 1;
-                               if (pservice->auto_freq && (NULL != pservice->reg_pproc))
-                                       can_set = 0;
-                       } break;
-                       case VPU_PP : {
-                               if (NULL == pservice->reg_codec) {
-                                       if (NULL == pservice->reg_pproc)
-                                               can_set = 1;
-                               } else {
-                                       if ((VPU_DEC == pservice->reg_codec->type) && (NULL == pservice->reg_pproc))
-                                               can_set = 1;
-                                       /* can not charge frequency when vpu is working */
-                                       if (pservice->auto_freq)
-                                               can_set = 0;
-                               }
-                       } break;
-                       case VPU_DEC_PP : {
-                               if (change_able)
-                                       can_set = 1;
-                               } break;
-                       default : {
-                               printk("undefined reg type %d\n", reg->type);
-                       } break;
-                       }
-               }
-
-               // then check reset request
-               if (reset_request && !change_able)
-                       reset_request = 0;
-
-               // do reset before setting registers
-               if (reset_request)
-                       vpu_reset(data);
-
-               if (can_set) {
-                       reg_from_wait_to_run(pservice, reg);
-                       reg_copy_to_hw(reg->data, reg);
-               }
-       }
-       vpu_debug_leave();
-}
-
-static int return_reg(struct vpu_subdev_data *data,
-       vpu_reg *reg, u32 __user *dst)
-{
-       int ret = 0;
-       vpu_debug_enter();
-       switch (reg->type) {
-       case VPU_ENC : {
-               if (copy_to_user(dst, &reg->reg[0], data->hw_info->enc_io_size))
-                       ret = -EFAULT;
-               break;
-       }
-       case VPU_DEC : {
-               int reg_len = data->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC;
-               if (copy_to_user(dst, &reg->reg[0], SIZE_REG(reg_len)))
-                       ret = -EFAULT;
-               break;
-       }
-       case VPU_PP : {
-               if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_PP)))
-                       ret = -EFAULT;
-               break;
-       }
-       case VPU_DEC_PP : {
-               if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_DEC_PP)))
-                       ret = -EFAULT;
-               break;
-       }
-       default : {
-               ret = -EFAULT;
-               vpu_err("error: copy reg to user with unknown type %d\n", reg->type);
-               break;
-       }
-       }
-       reg_deinit(data, reg);
-       vpu_debug_leave();
-       return ret;
-}
-
-static long vpu_service_ioctl(struct file *filp, unsigned int cmd,
-       unsigned long arg)
-{
-       struct vpu_subdev_data *data =
-               container_of(filp->f_dentry->d_inode->i_cdev,
-                       struct vpu_subdev_data, cdev);
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_session *session = (vpu_session *)filp->private_data;
-       vpu_debug_enter();
-       if (NULL == session)
-               return -EINVAL;
-
-       switch (cmd) {
-       case VPU_IOC_SET_CLIENT_TYPE : {
-               session->type = (enum VPU_CLIENT_TYPE)arg;
-               vpu_debug(DEBUG_IOCTL, "VPU_IOC_SET_CLIENT_TYPE %d\n", session->type);
-               break;
-       }
-       case VPU_IOC_GET_HW_FUSE_STATUS : {
-               struct vpu_request req;
-               vpu_debug(DEBUG_IOCTL, "VPU_IOC_GET_HW_FUSE_STATUS type %d\n", session->type);
-               if (copy_from_user(&req, (void __user *)arg, sizeof(struct vpu_request))) {
-                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n");
-                       return -EFAULT;
-               } else {
-                       if (VPU_ENC != session->type) {
-                               if (copy_to_user((void __user *)req.req,
-                                       &pservice->dec_config,
-                                       sizeof(struct vpu_dec_config))) {
-                                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n",
-                                               session->type);
-                                       return -EFAULT;
-                               }
-                       } else {
-                               if (copy_to_user((void __user *)req.req,
-                                       &pservice->enc_config,
-                                       sizeof(struct vpu_enc_config ))) {
-                                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n",
-                                               session->type);
-                                       return -EFAULT;
-                               }
-                       }
-               }
-
-               break;
-       }
-       case VPU_IOC_SET_REG : {
-               struct vpu_request req;
-               vpu_reg *reg;
-               vpu_debug(DEBUG_IOCTL, "VPU_IOC_SET_REG type %d\n", session->type);
-               if (copy_from_user(&req, (void __user *)arg,
-                       sizeof(struct vpu_request))) {
-                       vpu_err("error: VPU_IOC_SET_REG copy_from_user failed\n");
-                       return -EFAULT;
-               }
-               reg = reg_init(data, session,
-                       (void __user *)req.req, req.size);
-               if (NULL == reg) {
-                       return -EFAULT;
-               } else {
-                       mutex_lock(&pservice->lock);
-                       try_set_reg(data);
-                       mutex_unlock(&pservice->lock);
-               }
-
-               break;
-       }
-       case VPU_IOC_GET_REG : {
-               struct vpu_request req;
-               vpu_reg *reg;
-               vpu_debug(DEBUG_IOCTL, "VPU_IOC_GET_REG type %d\n", session->type);
-               if (copy_from_user(&req, (void __user *)arg,
-                       sizeof(struct vpu_request))) {
-                       vpu_err("error: VPU_IOC_GET_REG copy_from_user failed\n");
-                       return -EFAULT;
-               } else {
-                       int ret = wait_event_timeout(session->wait, !list_empty(&session->done), VPU_TIMEOUT_DELAY);
-                       if (!list_empty(&session->done)) {
-                               if (ret < 0) {
-                                       vpu_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret);
-                               }
-                               ret = 0;
-                       } else {
-                               if (unlikely(ret < 0)) {
-                                       vpu_err("error: pid %d wait task ret %d\n", session->pid, ret);
-                               } else if (0 == ret) {
-                                       vpu_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));
-                                       ret = -ETIMEDOUT;
-                               }
-                       }
-                       if (ret < 0) {
-                               int task_running = atomic_read(&session->task_running);
-                               mutex_lock(&pservice->lock);
-                               vpu_service_dump(pservice);
-                               if (task_running) {
-                                       atomic_set(&session->task_running, 0);
-                                       atomic_sub(task_running, &pservice->total_running);
-                                       printk("%d task is running but not return, reset hardware...", task_running);
-                                       vpu_reset(data);
-                                       printk("done\n");
-                               }
-                               vpu_service_session_clear(data, session);
-                               mutex_unlock(&pservice->lock);
-                               return ret;
-                       }
-               }
-               mutex_lock(&pservice->lock);
-               reg = list_entry(session->done.next, vpu_reg, session_link);
-               return_reg(data, reg, (u32 __user *)req.req);
-               mutex_unlock(&pservice->lock);
-               break;
-       }
-       case VPU_IOC_PROBE_IOMMU_STATUS: {
-               int iommu_enable = 0;
-
-               vpu_debug(DEBUG_IOCTL, "VPU_IOC_PROBE_IOMMU_STATUS\n");
-
-#if defined(CONFIG_VCODEC_MMU)
-               iommu_enable = data->mmu_dev ? 1 : 0;
-#endif
-
-               if (copy_to_user((void __user *)arg, &iommu_enable, sizeof(int))) {
-                       vpu_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n");
-                       return -EFAULT;
-               }
-               break;
-       }
-       default : {
-               vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
-               break;
-       }
-       }
-       vpu_debug_leave();
-       return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long compat_vpu_service_ioctl(struct file *filp, unsigned int cmd,
-       unsigned long arg)
-{
-       struct vpu_subdev_data *data =
-               container_of(filp->f_dentry->d_inode->i_cdev,
-                       struct vpu_subdev_data, cdev);
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_session *session = (vpu_session *)filp->private_data;
-       vpu_debug_enter();
-       vpu_debug(3, "cmd %x, COMPAT_VPU_IOC_SET_CLIENT_TYPE %x\n", cmd,
-                 (u32)COMPAT_VPU_IOC_SET_CLIENT_TYPE);
-       if (NULL == session)
-               return -EINVAL;
-
-       switch (cmd) {
-       case COMPAT_VPU_IOC_SET_CLIENT_TYPE : {
-               session->type = (enum VPU_CLIENT_TYPE)arg;
-               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_SET_CLIENT_TYPE type %d\n", session->type);
-               break;
-       }
-       case COMPAT_VPU_IOC_GET_HW_FUSE_STATUS : {
-               struct compat_vpu_request req;
-               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_GET_HW_FUSE_STATUS type %d\n", session->type);
-               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
-                                  sizeof(struct compat_vpu_request))) {
-                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS"
-                               " copy_from_user failed\n");
-                       return -EFAULT;
-               } else {
-                       if (VPU_ENC != session->type) {
-                               if (copy_to_user(compat_ptr((compat_uptr_t)req.req),
-                                                &pservice->dec_config,
-                                                sizeof(struct vpu_dec_config))) {
-                                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS "
-                                               "copy_to_user failed type %d\n",
-                                               session->type);
-                                       return -EFAULT;
-                               }
-                       } else {
-                               if (copy_to_user(compat_ptr((compat_uptr_t)req.req),
-                                                &pservice->enc_config,
-                                                sizeof(struct vpu_enc_config ))) {
-                                       vpu_err("error: VPU_IOC_GET_HW_FUSE_STATUS"
-                                               " copy_to_user failed type %d\n",
-                                               session->type);
-                                       return -EFAULT;
-                               }
-                       }
-               }
-
-               break;
-       }
-       case COMPAT_VPU_IOC_SET_REG : {
-               struct compat_vpu_request req;
-               vpu_reg *reg;
-               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_SET_REG type %d\n", session->type);
-               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
-                                  sizeof(struct compat_vpu_request))) {
-                       vpu_err("VPU_IOC_SET_REG copy_from_user failed\n");
-                       return -EFAULT;
-               }
-               reg = reg_init(data, session,
-                              compat_ptr((compat_uptr_t)req.req), req.size);
-               if (NULL == reg) {
-                       return -EFAULT;
-               } else {
-                       mutex_lock(&pservice->lock);
-                       try_set_reg(data);
-                       mutex_unlock(&pservice->lock);
-               }
-
-               break;
-       }
-       case COMPAT_VPU_IOC_GET_REG : {
-               struct compat_vpu_request req;
-               vpu_reg *reg;
-               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_GET_REG type %d\n", session->type);
-               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
-                                  sizeof(struct compat_vpu_request))) {
-                       vpu_err("VPU_IOC_GET_REG copy_from_user failed\n");
-                       return -EFAULT;
-               } else {
-                       int ret = wait_event_timeout(session->wait, !list_empty(&session->done), VPU_TIMEOUT_DELAY);
-                       if (!list_empty(&session->done)) {
-                               if (ret < 0) {
-                                       vpu_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret);
-                               }
-                               ret = 0;
-                       } else {
-                               if (unlikely(ret < 0)) {
-                                       vpu_err("error: pid %d wait task ret %d\n", session->pid, ret);
-                               } else if (0 == ret) {
-                                       vpu_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));
-                                       ret = -ETIMEDOUT;
-                               }
-                       }
-                       if (ret < 0) {
-                               int task_running = atomic_read(&session->task_running);
-                               mutex_lock(&pservice->lock);
-                               vpu_service_dump(pservice);
-                               if (task_running) {
-                                       atomic_set(&session->task_running, 0);
-                                       atomic_sub(task_running, &pservice->total_running);
-                                       printk("%d task is running but not return, reset hardware...", task_running);
-                                       vpu_reset(data);
-                                       printk("done\n");
-                               }
-                               vpu_service_session_clear(data, session);
-                               mutex_unlock(&pservice->lock);
-                               return ret;
-                       }
-               }
-               mutex_lock(&pservice->lock);
-               reg = list_entry(session->done.next, vpu_reg, session_link);
-               return_reg(data, reg, compat_ptr((compat_uptr_t)req.req));
-               mutex_unlock(&pservice->lock);
-               break;
-       }
-       case COMPAT_VPU_IOC_PROBE_IOMMU_STATUS : {
-               int iommu_enable = 0;
-
-               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_PROBE_IOMMU_STATUS\n");
-#if defined(CONFIG_VCODEC_MMU)
-               iommu_enable = data->mmu_dev ? 1 : 0;
-#endif
-
-               if (copy_to_user(compat_ptr((compat_uptr_t)arg), &iommu_enable, sizeof(int))) {
-                       vpu_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n");
-                       return -EFAULT;
-               }
-               break;
-       }
-       default : {
-               vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
-               break;
-       }
-       }
-       vpu_debug_leave();
-       return 0;
-}
-#endif
-
-static int vpu_service_check_hw(struct vpu_subdev_data *data, u32 hw_addr)
-{
-       int ret = -EINVAL, i = 0;
-       volatile u32 *tmp = (volatile u32 *)ioremap_nocache(hw_addr, 0x4);
-       u32 enc_id = *tmp;
-
-       enc_id = (enc_id >> 16) & 0xFFFF;
-       pr_info("checking hw id %x\n", enc_id);
-       data->hw_info = NULL;
-       for (i = 0; i < ARRAY_SIZE(vpu_hw_set); i++) {
-               if (enc_id == vpu_hw_set[i].hw_id) {
-                       data->hw_info = &vpu_hw_set[i];
-                       ret = 0;
-                       break;
-               }
-       }
-       iounmap((void *)tmp);
-       return ret;
-}
-
-static int vpu_service_open(struct inode *inode, struct file *filp)
-{
-       struct vpu_subdev_data *data = container_of(inode->i_cdev, struct vpu_subdev_data, cdev);
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL);
-
-       vpu_debug_enter();
-
-       if (NULL == session) {
-               vpu_err("error: unable to allocate memory for vpu_session.");
-               return -ENOMEM;
-       }
-
-       session->type   = VPU_TYPE_BUTT;
-       session->pid    = current->pid;
-       INIT_LIST_HEAD(&session->waiting);
-       INIT_LIST_HEAD(&session->running);
-       INIT_LIST_HEAD(&session->done);
-       INIT_LIST_HEAD(&session->list_session);
-       init_waitqueue_head(&session->wait);
-       atomic_set(&session->task_running, 0);
-       mutex_lock(&pservice->lock);
-       list_add_tail(&session->list_session, &pservice->session);
-       filp->private_data = (void *)session;
-       mutex_unlock(&pservice->lock);
-
-       pr_debug("dev opened\n");
-       vpu_debug_leave();
-       return nonseekable_open(inode, filp);
-}
-
-static int vpu_service_release(struct inode *inode, struct file *filp)
-{
-       struct vpu_subdev_data *data = container_of(inode->i_cdev, struct vpu_subdev_data, cdev);
-       struct vpu_service_info *pservice = data->pservice;
-       int task_running;
-       vpu_session *session = (vpu_session *)filp->private_data;
-       vpu_debug_enter();
-       if (NULL == session)
-               return -EINVAL;
-
-       task_running = atomic_read(&session->task_running);
-       if (task_running) {
-               vpu_err("error: vpu_service session %d still has %d task running when closing\n", session->pid, task_running);
-               msleep(50);
-       }
-       wake_up(&session->wait);
-
-       mutex_lock(&pservice->lock);
-       /* remove this filp from the asynchronusly notified filp's */
-       list_del_init(&session->list_session);
-       vpu_service_session_clear(data, session);
-       kfree(session);
-       filp->private_data = NULL;
-       mutex_unlock(&pservice->lock);
-
-       pr_debug("dev closed\n");
-       vpu_debug_leave();
-       return 0;
-}
-
-static const struct file_operations vpu_service_fops = {
-       .unlocked_ioctl = vpu_service_ioctl,
-       .open           = vpu_service_open,
-       .release        = vpu_service_release,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = compat_vpu_service_ioctl,
-#endif
-};
-
-static irqreturn_t vdpu_irq(int irq, void *dev_id);
-static irqreturn_t vdpu_isr(int irq, void *dev_id);
-static irqreturn_t vepu_irq(int irq, void *dev_id);
-static irqreturn_t vepu_isr(int irq, void *dev_id);
-static void get_hw_info(struct vpu_subdev_data *data);
-
-#ifdef CONFIG_VCODEC_MMU
-static struct device *rockchip_get_sysmmu_dev(const char *compt)
-{
-       struct device_node *dn = NULL;
-       struct platform_device *pd = NULL;
-       struct device *ret = NULL ;
-
-       dn = of_find_compatible_node(NULL,NULL,compt);
-       if(!dn) {
-               printk("can't find device node %s \r\n",compt);
-               return NULL;
-       }
-
-       pd = of_find_device_by_node(dn);
-       if(!pd) {
-               printk("can't find platform device in device node %s\n",compt);
-               return  NULL;
-       }
-       ret = &pd->dev;
-
-       return ret;
-
-}
-#ifdef CONFIG_IOMMU_API
-static inline void platform_set_sysmmu(struct device *iommu,
-       struct device *dev)
-{
-       dev->archdata.iommu = iommu;
-}
-#else
-static inline void platform_set_sysmmu(struct device *iommu,
-       struct device *dev)
-{
-}
-#endif
-
-int vcodec_sysmmu_fault_hdl(struct device *dev,
-                               enum rk_iommu_inttype itype,
-                               unsigned long pgtable_base,
-                               unsigned long fault_addr, unsigned int status)
-{
-       struct platform_device *pdev;
-       struct vpu_subdev_data *data;
-       struct vpu_service_info *pservice;
-
-       vpu_debug_enter();
-
-       pdev = container_of(dev, struct platform_device, dev);
-
-       data = platform_get_drvdata(pdev);
-       pservice = data->pservice;
-
-       if (pservice->reg_codec) {
-               struct vcodec_mem_region *mem, *n;
-               int i = 0;
-               vpu_debug(DEBUG_IOMMU, "vcodec, fault addr 0x%08x\n", (u32)fault_addr);
-               list_for_each_entry_safe(mem, n,
-                                        &pservice->reg_codec->mem_region_list,
-                                        reg_lnk) {
-                       vpu_debug(DEBUG_IOMMU, "vcodec, reg[%02u] mem region [%02d] 0x%08x %ld\n",
-                               mem->reg_idx, i, (u32)mem->iova, mem->len);
-                       i++;
-               }
-
-               pr_alert("vcodec, page fault occur, reset hw\n");
-               pservice->reg_codec->reg[101] = 1;
-               vpu_reset(data);
-       }
-
-       return 0;
-}
-#endif
-
-#if HEVC_TEST_ENABLE
-static int hevc_test_case0(vpu_service_info *pservice);
-#endif
-#if defined(CONFIG_ION_ROCKCHIP)
-extern struct ion_client *rockchip_ion_client_create(const char * name);
-#endif
-
-static int vcodec_subdev_probe(struct platform_device *pdev,
-       struct vpu_service_info *pservice)
-{
-       int ret = 0;
-       struct resource *res = NULL;
-       u32 ioaddr = 0;
-       struct device *dev = &pdev->dev;
-       char *name = (char*)dev_name(dev);
-       struct device_node *np = pdev->dev.of_node;
-       struct vpu_subdev_data *data =
-               devm_kzalloc(dev, sizeof(struct vpu_subdev_data), GFP_KERNEL);
-#if defined(CONFIG_VCODEC_MMU)
-       u32 iommu_en = 0;
-       char mmu_dev_dts_name[40];
-       of_property_read_u32(np, "iommu_enabled", &iommu_en);
-#endif
-       pr_info("probe device %s\n", dev_name(dev));
-
-       data->pservice = pservice;
-       data->dev = dev;
-
-       of_property_read_string(np, "name", (const char**)&name);
-       of_property_read_u32(np, "dev_mode", (u32*)&data->mode);
-       /*dev_set_name(dev, name);*/
-
-       if (pservice->reg_base == 0) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               data->regs = devm_ioremap_resource(dev, res);
-               if (IS_ERR(data->regs)) {
-                       ret = PTR_ERR(data->regs);
-                       goto err;
-               }
-               ioaddr = res->start;
-       } else {
-               data->regs = pservice->reg_base;
-               ioaddr = pservice->ioaddr;
-       }
-
-       clear_bit(MMU_ACTIVATED, &data->state);
-       vcodec_enter_mode(data);
-       ret = vpu_service_check_hw(data, ioaddr);
-       if (ret < 0) {
-               vpu_err("error: hw info check faild\n");
-               goto err;
-       }
-
-       data->dec_dev.iosize = data->hw_info->dec_io_size;
-       data->dec_dev.hwregs = (volatile u32 *)((u8 *)data->regs + data->hw_info->dec_offset);
-       data->reg_size = data->dec_dev.iosize;
-
-       if (data->mode == VCODEC_RUNNING_MODE_VPU) {
-               data->enc_dev.iosize = data->hw_info->enc_io_size;
-               data->reg_size = data->reg_size > data->enc_dev.iosize ? data->reg_size : data->enc_dev.iosize;
-               data->enc_dev.hwregs = (volatile u32 *)((u8 *)data->regs + data->hw_info->enc_offset);
-       }
-
-       data->irq_enc = platform_get_irq_byname(pdev, "irq_enc");
-       if (data->irq_enc > 0) {
-               ret = devm_request_threaded_irq(dev,
-                       data->irq_enc, vepu_irq, vepu_isr,
-                       IRQF_SHARED, dev_name(dev),
-                       (void *)data);
-               if (ret) {
-                       dev_err(dev,
-                               "error: can't request vepu irq %d\n",
-                               data->irq_enc);
-                       goto err;
-               }
-       }
-       data->irq_dec = platform_get_irq_byname(pdev, "irq_dec");
-       if (data->irq_dec > 0) {
-               ret = devm_request_threaded_irq(dev,
-                       data->irq_dec, vdpu_irq, vdpu_isr,
-                       IRQF_SHARED, dev_name(dev),
-                       (void *)data);
-               if (ret) {
-                       dev_err(dev,
-                               "error: can't request vdpu irq %d\n",
-                               data->irq_dec);
-                       goto err;
-               }
-       }
-       atomic_set(&data->dec_dev.irq_count_codec, 0);
-       atomic_set(&data->dec_dev.irq_count_pp, 0);
-       atomic_set(&data->enc_dev.irq_count_codec, 0);
-       atomic_set(&data->enc_dev.irq_count_pp, 0);
-#if defined(CONFIG_VCODEC_MMU)
-       if (iommu_en) {
-               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
-                       sprintf(mmu_dev_dts_name,
-                               HEVC_IOMMU_COMPATIBLE_NAME);
-               else
-                       sprintf(mmu_dev_dts_name,
-                               VPU_IOMMU_COMPATIBLE_NAME);
-
-               data->mmu_dev =
-                       rockchip_get_sysmmu_dev(mmu_dev_dts_name);
-
-               if (data->mmu_dev)
-                       platform_set_sysmmu(data->mmu_dev, dev);
-
-               rockchip_iovmm_set_fault_handler(dev, vcodec_sysmmu_fault_hdl);
-       }
-#endif
-       get_hw_info(data);
-       pservice->auto_freq = true;
-
-       vcodec_exit_mode(data);
-       /* create device node */
-       ret = alloc_chrdev_region(&data->dev_t, 0, 1, name);
-       if (ret) {
-               dev_err(dev, "alloc dev_t failed\n");
-               goto err;
-       }
-
-       cdev_init(&data->cdev, &vpu_service_fops);
-
-       data->cdev.owner = THIS_MODULE;
-       data->cdev.ops = &vpu_service_fops;
-
-       ret = cdev_add(&data->cdev, data->dev_t, 1);
-
-       if (ret) {
-               dev_err(dev, "add dev_t failed\n");
-               goto err;
-       }
-
-       data->cls = class_create(THIS_MODULE, name);
-
-       if (IS_ERR(data->cls)) {
-               ret = PTR_ERR(data->cls);
-               dev_err(dev, "class_create err:%d\n", ret);
-               goto err;
-       }
-
-       data->child_dev = device_create(data->cls, dev,
-               data->dev_t, NULL, name);
-
-       platform_set_drvdata(pdev, data);
-
-       INIT_LIST_HEAD(&data->lnk_service);
-       list_add_tail(&data->lnk_service, &pservice->subdev_list);
-
-#ifdef CONFIG_DEBUG_FS
-       data->debugfs_dir =
-               vcodec_debugfs_create_device_dir((char*)name, parent);
-       if (data->debugfs_dir == NULL)
-               vpu_err("create debugfs dir %s failed\n", name);
-
-       data->debugfs_file_regs =
-               debugfs_create_file("regs", 0664,
-                                   data->debugfs_dir, data,
-                                   &debug_vcodec_fops);
-#endif
-       return 0;
-err:
-       if (data->irq_enc > 0)
-               free_irq(data->irq_enc, (void *)data);
-       if (data->irq_dec > 0)
-               free_irq(data->irq_dec, (void *)data);
-
-       if (data->child_dev) {
-               device_destroy(data->cls, data->dev_t);
-               cdev_del(&data->cdev);
-               unregister_chrdev_region(data->dev_t, 1);
-       }
-
-       if (data->cls)
-               class_destroy(data->cls);
-       return -1;
-}
-
-static void vcodec_subdev_remove(struct vpu_subdev_data *data)
-{
-       device_destroy(data->cls, data->dev_t);
-       class_destroy(data->cls);
-       cdev_del(&data->cdev);
-       unregister_chrdev_region(data->dev_t, 1);
-
-       free_irq(data->irq_enc, (void *)&data);
-       free_irq(data->irq_dec, (void *)&data);
-
-#ifdef CONFIG_DEBUG_FS
-       debugfs_remove_recursive(data->debugfs_dir);
-#endif
-}
-
-static void vcodec_read_property(struct device_node *np,
-       struct vpu_service_info *pservice)
-{
-       pservice->mode_bit = 0;
-       pservice->mode_ctrl = 0;
-       pservice->subcnt = 0;
-       pservice->grf_base = NULL;
-
-       of_property_read_u32(np, "subcnt", &pservice->subcnt);
-
-       if (pservice->subcnt > 1) {
-               of_property_read_u32(np, "mode_bit", &pservice->mode_bit);
-               of_property_read_u32(np, "mode_ctrl", &pservice->mode_ctrl);
-       }
-#ifdef CONFIG_MFD_SYSCON
-       pservice->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
-       if (IS_ERR_OR_NULL(pservice->grf)) {
-               pservice->grf = NULL;
-#ifdef CONFIG_ARM
-               pservice->grf_base = RK_GRF_VIRT;
-#else
-               vpu_err("can't find vpu grf property\n");
-               return;
-#endif
-       }
-#else
-#ifdef CONFIG_ARM
-       pservice->grf_base = RK_GRF_VIRT;
-#else
-       vpu_err("can't find vpu grf property\n");
-       return;
-#endif
-#endif
-
-#ifdef CONFIG_RESET_CONTROLLER
-       pservice->rst_a = devm_reset_control_get(pservice->dev, "video_a");
-       pservice->rst_h = devm_reset_control_get(pservice->dev, "video_h");
-       pservice->rst_v = devm_reset_control_get(pservice->dev, "video");
-
-       if (IS_ERR_OR_NULL(pservice->rst_a)) {
-               pr_warn("No reset resource define\n");
-               pservice->rst_a = NULL;
-       }
-
-       if (IS_ERR_OR_NULL(pservice->rst_h)) {
-               pr_warn("No reset resource define\n");
-               pservice->rst_h = NULL;
-       }
-
-       if (IS_ERR_OR_NULL(pservice->rst_v)) {
-               pr_warn("No reset resource define\n");
-               pservice->rst_v = NULL;
-       }
-#endif
-
-       of_property_read_string(np, "name", (const char**)&pservice->name);
-}
-
-static void vcodec_init_drvdata(struct vpu_service_info *pservice)
-{
-       pservice->dev_id = VCODEC_DEVICE_ID_VPU;
-       pservice->curr_mode = -1;
-
-       wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu");
-       INIT_LIST_HEAD(&pservice->waiting);
-       INIT_LIST_HEAD(&pservice->running);
-       mutex_init(&pservice->lock);
-
-       INIT_LIST_HEAD(&pservice->done);
-       INIT_LIST_HEAD(&pservice->session);
-       INIT_LIST_HEAD(&pservice->subdev_list);
-
-       pservice->reg_pproc     = NULL;
-       atomic_set(&pservice->total_running, 0);
-       atomic_set(&pservice->enabled,       0);
-       atomic_set(&pservice->power_on_cnt,  0);
-       atomic_set(&pservice->power_off_cnt, 0);
-       atomic_set(&pservice->reset_request, 0);
-
-       INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);
-
-       pservice->ion_client = rockchip_ion_client_create("vpu");
-       if (IS_ERR(pservice->ion_client)) {
-               vpu_err("failed to create ion client for vcodec ret %ld\n",
-                       PTR_ERR(pservice->ion_client));
-       } else {
-               vpu_debug(DEBUG_IOMMU, "vcodec ion client create success!\n");
-       }
-}
-
-static int vcodec_probe(struct platform_device *pdev)
-{
-       int i;
-       int ret = 0;
-       struct resource *res = NULL;
-       struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
-       struct vpu_service_info *pservice =
-               devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL);
-
-       pr_info("probe device %s\n", dev_name(dev));
-
-       pservice->dev = dev;
-
-       vcodec_read_property(np, pservice);
-       vcodec_init_drvdata(pservice);
-
-       if (strncmp(pservice->name, "hevc_service", 12) == 0)
-               pservice->dev_id = VCODEC_DEVICE_ID_HEVC;
-       else if (strncmp(pservice->name, "vpu_service", 11) == 0)
-               pservice->dev_id = VCODEC_DEVICE_ID_VPU;
-       else
-               pservice->dev_id = VCODEC_DEVICE_ID_COMBO;
-
-       if (0 > vpu_get_clk(pservice))
-               goto err;
-
-       vpu_service_power_on(pservice);
-
-       if (of_property_read_bool(np, "reg")) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-               pservice->reg_base = devm_ioremap_resource(pservice->dev, res);
-               if (IS_ERR(pservice->reg_base)) {
-                       vpu_err("ioremap registers base failed\n");
-                       ret = PTR_ERR(pservice->reg_base);
-                       goto err;
-               }
-               pservice->ioaddr = res->start;
-       } else {
-               pservice->reg_base = 0;
-       }
-
-       if (of_property_read_bool(np, "subcnt")) {
-               for (i = 0; i<pservice->subcnt; i++) {
-                       struct device_node *sub_np;
-                       struct platform_device *sub_pdev;
-                       sub_np = of_parse_phandle(np, "rockchip,sub", i);
-                       sub_pdev = of_find_device_by_node(sub_np);
-
-                       vcodec_subdev_probe(sub_pdev, pservice);
-               }
-       } else {
-               vcodec_subdev_probe(pdev, pservice);
-       }
-       platform_set_drvdata(pdev, pservice);
-
-       vpu_service_power_off(pservice);
-
-       pr_info("init success\n");
-
-       return 0;
-
-err:
-       pr_info("init failed\n");
-       vpu_service_power_off(pservice);
-       vpu_put_clk(pservice);
-       wake_lock_destroy(&pservice->wake_lock);
-
-       if (res)
-               devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-
-       return ret;
-}
-
-static int vcodec_remove(struct platform_device *pdev)
-{
-       struct vpu_service_info *pservice = platform_get_drvdata(pdev);
-       struct resource *res;
-       struct vpu_subdev_data *data, *n;
-
-       list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) {
-               vcodec_subdev_remove(data);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-       vpu_put_clk(pservice);
-       wake_lock_destroy(&pservice->wake_lock);
-
-       return 0;
-}
-
-#if defined(CONFIG_OF)
-static const struct of_device_id vcodec_service_dt_ids[] = {
-       {.compatible = "vpu_service",},
-       {.compatible = "rockchip,hevc_service",},
-       {.compatible = "rockchip,vpu_combo",},
-       {},
-};
-#endif
-
-static struct platform_driver vcodec_driver = {
-       .probe = vcodec_probe,
-       .remove = vcodec_remove,
-       .driver = {
-               .name = "vcodec",
-               .owner = THIS_MODULE,
-#if defined(CONFIG_OF)
-               .of_match_table = of_match_ptr(vcodec_service_dt_ids),
-#endif
-       },
-};
-
-static void get_hw_info(struct vpu_subdev_data *data)
-{
-       struct vpu_service_info *pservice = data->pservice;
-       struct vpu_dec_config *dec = &pservice->dec_config;
-       struct vpu_enc_config *enc = &pservice->enc_config;
-       if (data->mode == VCODEC_RUNNING_MODE_VPU) {
-               u32 configReg   = data->dec_dev.hwregs[VPU_DEC_HWCFG0];
-               u32 asicID      = data->dec_dev.hwregs[0];
-
-               dec->h264_support    = (configReg >> DWL_H264_E) & 0x3U;
-               dec->jpegSupport    = (configReg >> DWL_JPEG_E) & 0x01U;
-               if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U))
-                       dec->jpegSupport = JPEG_PROGRESSIVE;
-               dec->mpeg4Support   = (configReg >> DWL_MPEG4_E) & 0x3U;
-               dec->vc1Support     = (configReg >> DWL_VC1_E) & 0x3U;
-               dec->mpeg2Support   = (configReg >> DWL_MPEG2_E) & 0x01U;
-               dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U;
-               dec->refBufSupport  = (configReg >> DWL_REF_BUFF_E) & 0x01U;
-               dec->vp6Support     = (configReg >> DWL_VP6_E) & 0x01U;
-
-               dec->maxDecPicWidth = 4096;
-
-               /* 2nd Config register */
-               configReg   = data->dec_dev.hwregs[VPU_DEC_HWCFG1];
-               if (dec->refBufSupport) {
-                       if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U)
-                               dec->refBufSupport |= 2;
-                       if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U)
-                               dec->refBufSupport |= 4;
-               }
-               dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U;
-               dec->vp7Support     = (configReg >> DWL_VP7_E) & 0x01U;
-               dec->vp8Support     = (configReg >> DWL_VP8_E) & 0x01U;
-               dec->avsSupport     = (configReg >> DWL_AVS_E) & 0x01U;
-
-               /* JPEG xtensions */
-               if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U))
-                       dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U;
-               else
-                       dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED;
-
-               if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) )
-                       dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U;
-               else
-                       dec->rvSupport = RV_NOT_SUPPORTED;
-               dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U;
-
-               if (dec->refBufSupport && (asicID >> 16) == 0x6731U )
-                       dec->refBufSupport |= 8; /* enable HW support for offset */
-
-               if (!cpu_is_rk3036()) {
-                       configReg = data->enc_dev.hwregs[63];
-                       enc->maxEncodedWidth = configReg & ((1 << 11) - 1);
-                       enc->h264Enabled = (configReg >> 27) & 1;
-                       enc->mpeg4Enabled = (configReg >> 26) & 1;
-                       enc->jpegEnabled = (configReg >> 25) & 1;
-                       enc->vsEnabled = (configReg >> 24) & 1;
-                       enc->rgbEnabled = (configReg >> 28) & 1;
-                       enc->reg_size = data->reg_size;
-                       enc->reserv[0] = enc->reserv[1] = 0;
-               }
-               pservice->auto_freq = true;
-               vpu_debug(DEBUG_EXTRA_INFO, "vpu_service set to auto frequency mode\n");
-               atomic_set(&pservice->freq_status, VPU_FREQ_BUT);
-
-               pservice->bug_dec_addr = cpu_is_rk30xx();
-       } else {
-               if (cpu_is_rk3036()  || cpu_is_rk312x())
-                       dec->maxDecPicWidth = 1920;
-               else
-                       dec->maxDecPicWidth = 4096;
-               /* disable frequency switch in hevc.*/
-               pservice->auto_freq = false;
-       }
-}
-
-static bool check_irq_err(task_info *task, u32 irq_status)
-{
-       return (task->error_mask & irq_status) ? true : false;
-}
-
-static irqreturn_t vdpu_irq(int irq, void *dev_id)
-{
-       struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id;
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_device *dev = &data->dec_dev;
-       u32 raw_status;
-       u32 dec_status;
-
-       /*vcodec_enter_mode(data);*/
-
-       dec_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
-
-       if (dec_status & DEC_INTERRUPT_BIT) {
-               time_record(&tasks[TASK_VPU_DEC], 1);
-               vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq dec status %08x\n", dec_status);
-               if ((dec_status & 0x40001) == 0x40001) {
-                       do {
-                               dec_status =
-                                       readl(dev->hwregs +
-                                               DEC_INTERRUPT_REGISTER);
-                       } while ((dec_status & 0x40001) == 0x40001);
-               }
-
-               if (check_irq_err((data->hw_info->hw_id == HEVC_ID)?
-                                       (&tasks[TASK_RKDEC_HEVC]) : (&tasks[TASK_VPU_DEC]),
-                                       dec_status)) {
-                       atomic_add(1, &pservice->reset_request);
-               }
-
-               writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER);
-               atomic_add(1, &dev->irq_count_codec);
-               time_diff(&tasks[TASK_VPU_DEC]);
-       }
-
-       if (data->hw_info->hw_id != HEVC_ID) {
-               u32 pp_status = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
-               if (pp_status & PP_INTERRUPT_BIT) {
-                       time_record(&tasks[TASK_VPU_PP], 1);
-                       vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq pp status %08x\n", pp_status);
-
-                       if (check_irq_err(&tasks[TASK_VPU_PP], dec_status))
-                               atomic_add(1, &pservice->reset_request);
-
-                       /* clear pp IRQ */
-                       writel(pp_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
-                       atomic_add(1, &dev->irq_count_pp);
-                       time_diff(&tasks[TASK_VPU_PP]);
-               }
-       }
-
-       pservice->irq_status = raw_status;
-
-       /*vcodec_exit_mode(pservice);*/
-
-       if (atomic_read(&dev->irq_count_pp) ||
-           atomic_read(&dev->irq_count_codec))
-               return IRQ_WAKE_THREAD;
-       else
-               return IRQ_NONE;
-}
-
-static irqreturn_t vdpu_isr(int irq, void *dev_id)
-{
-       struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id;
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_device *dev = &data->dec_dev;
-
-       mutex_lock(&pservice->lock);
-       if (atomic_read(&dev->irq_count_codec)) {
-               atomic_sub(1, &dev->irq_count_codec);
-               if (NULL == pservice->reg_codec) {
-                       vpu_err("error: dec isr with no task waiting\n");
-               } else {
-                       reg_from_run_to_done(data, pservice->reg_codec);
-                       /* avoid vpu timeout and can't recover problem */
-                       VDPU_SOFT_RESET(data->regs);
-               }
-       }
-
-       if (atomic_read(&dev->irq_count_pp)) {
-               atomic_sub(1, &dev->irq_count_pp);
-               if (NULL == pservice->reg_pproc) {
-                       vpu_err("error: pp isr with no task waiting\n");
-               } else {
-                       reg_from_run_to_done(data, pservice->reg_pproc);
-               }
-       }
-       try_set_reg(data);
-       mutex_unlock(&pservice->lock);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t vepu_irq(int irq, void *dev_id)
-{
-       struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id;
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_device *dev = &data->enc_dev;
-       u32 irq_status;
-
-       /*vcodec_enter_mode(data);*/
-       irq_status= readl(dev->hwregs + ENC_INTERRUPT_REGISTER);
-
-       vpu_debug(DEBUG_IRQ_STATUS, "vepu_irq irq status %x\n", irq_status);
-
-       if (likely(irq_status & ENC_INTERRUPT_BIT)) {
-               time_record(&tasks[TASK_VPU_ENC], 1);
-
-               if (check_irq_err(&tasks[TASK_VPU_ENC], irq_status))
-                       atomic_add(1, &pservice->reset_request);
-
-               /* clear enc IRQ */
-               writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);
-               atomic_add(1, &dev->irq_count_codec);
-               time_diff(&tasks[TASK_VPU_ENC]);
-       }
-
-       pservice->irq_status = irq_status;
-
-       /*vcodec_exit_mode(pservice);*/
-
-       if (atomic_read(&dev->irq_count_codec))
-               return IRQ_WAKE_THREAD;
-       else
-               return IRQ_NONE;
-}
-
-static irqreturn_t vepu_isr(int irq, void *dev_id)
-{
-       struct vpu_subdev_data *data = (struct vpu_subdev_data*)dev_id;
-       struct vpu_service_info *pservice = data->pservice;
-       vpu_device *dev = &data->enc_dev;
-
-       mutex_lock(&pservice->lock);
-       if (atomic_read(&dev->irq_count_codec)) {
-               atomic_sub(1, &dev->irq_count_codec);
-               if (NULL == pservice->reg_codec) {
-                       vpu_err("error: enc isr with no task waiting\n");
-               } else {
-                       reg_from_run_to_done(data, pservice->reg_codec);
-               }
-       }
-       try_set_reg(data);
-       mutex_unlock(&pservice->lock);
-       return IRQ_HANDLED;
-}
-
-static int __init vcodec_service_init(void)
-{
-       int ret;
-
-       if ((ret = platform_driver_register(&vcodec_driver)) != 0) {
-               vpu_err("Platform device register failed (%d).\n", ret);
-               return ret;
-       }
-
-#ifdef CONFIG_DEBUG_FS
-       vcodec_debugfs_init();
-#endif
-
-       return ret;
-}
-
-static void __exit vcodec_service_exit(void)
-{
-#ifdef CONFIG_DEBUG_FS
-       vcodec_debugfs_exit();
-#endif
-
-       platform_driver_unregister(&vcodec_driver);
-}
-
-module_init(vcodec_service_init);
-module_exit(vcodec_service_exit);
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
-static int vcodec_debugfs_init()
-{
-       parent = debugfs_create_dir("vcodec", NULL);
-       if (!parent)
-               return -1;
-
-       return 0;
-}
-
-static void vcodec_debugfs_exit()
-{
-       debugfs_remove(parent);
-}
-
-static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent)
-{
-       return debugfs_create_dir(dirname, parent);
-}
-
-static int debug_vcodec_show(struct seq_file *s, void *unused)
-{
-       struct vpu_subdev_data *data = s->private;
-       struct vpu_service_info *pservice = data->pservice;
-       unsigned int i, n;
-       vpu_reg *reg, *reg_tmp;
-       vpu_session *session, *session_tmp;
-
-       mutex_lock(&pservice->lock);
-       vpu_service_power_on(pservice);
-       if (data->hw_info->hw_id != HEVC_ID) {
-               seq_printf(s, "\nENC Registers:\n");
-               n = data->enc_dev.iosize >> 2;
-               for (i = 0; i < n; i++)
-                       seq_printf(s, "\tswreg%d = %08X\n", i, readl(data->enc_dev.hwregs + i));
-       }
-       seq_printf(s, "\nDEC Registers:\n");
-       n = data->dec_dev.iosize >> 2;
-       for (i = 0; i < n; i++)
-               seq_printf(s, "\tswreg%d = %08X\n", i, readl(data->dec_dev.hwregs + i));
-
-       seq_printf(s, "\nvpu service status:\n");
-       list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) {
-               seq_printf(s, "session pid %d type %d:\n", session->pid, session->type);
-               /*seq_printf(s, "waiting reg set %d\n");*/
-               list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {
-                       seq_printf(s, "waiting register set\n");
-               }
-               list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {
-                       seq_printf(s, "running register set\n");
-               }
-               list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {
-                       seq_printf(s, "done    register set\n");
-               }
-       }
-
-       seq_printf(s, "\npower counter: on %d off %d\n",
-                       atomic_read(&pservice->power_on_cnt),
-                       atomic_read(&pservice->power_off_cnt));
-       mutex_unlock(&pservice->lock);
-       vpu_service_power_off(pservice);
-
-       return 0;
-}
-
-static int debug_vcodec_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, debug_vcodec_show, inode->i_private);
-}
-
-#endif
-
-#if HEVC_TEST_ENABLE & defined(CONFIG_ION_ROCKCHIP)
-#include "hevc_test_inc/pps_00.h"
-#include "hevc_test_inc/register_00.h"
-#include "hevc_test_inc/rps_00.h"
-#include "hevc_test_inc/scaling_list_00.h"
-#include "hevc_test_inc/stream_00.h"
-
-#include "hevc_test_inc/pps_01.h"
-#include "hevc_test_inc/register_01.h"
-#include "hevc_test_inc/rps_01.h"
-#include "hevc_test_inc/scaling_list_01.h"
-#include "hevc_test_inc/stream_01.h"
-
-#include "hevc_test_inc/cabac.h"
-
-extern struct ion_client *rockchip_ion_client_create(const char * name);
-
-static struct ion_client *ion_client = NULL;
-u8* get_align_ptr(u8* tbl, int len, u32 *phy)
-{
-       int size = (len+15) & (~15);
-       struct ion_handle *handle;
-       u8 *ptr;
-
-       if (ion_client == NULL)
-               ion_client = rockchip_ion_client_create("vcodec");
-
-       handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0);
-
-       ptr = ion_map_kernel(ion_client, handle);
-
-       ion_phys(ion_client, handle, phy, &size);
-
-       memcpy(ptr, tbl, len);
-
-       return ptr;
-}
-
-u8* get_align_ptr_no_copy(int len, u32 *phy)
-{
-       int size = (len+15) & (~15);
-       struct ion_handle *handle;
-       u8 *ptr;
-
-       if (ion_client == NULL)
-               ion_client = rockchip_ion_client_create("vcodec");
-
-       handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0);
-
-       ptr = ion_map_kernel(ion_client, handle);
-
-       ion_phys(ion_client, handle, phy, &size);
-
-       return ptr;
-}
-
-#define TEST_CNT    2
-static int hevc_test_case0(vpu_service_info *pservice)
-{
-       vpu_session session;
-       vpu_reg *reg;
-       unsigned long size = 272;
-       int testidx = 0;
-       int ret = 0;
-       u8 *pps_tbl[TEST_CNT];
-       u8 *register_tbl[TEST_CNT];
-       u8 *rps_tbl[TEST_CNT];
-       u8 *scaling_list_tbl[TEST_CNT];
-       u8 *stream_tbl[TEST_CNT];
-
-       int stream_size[2];
-       int pps_size[2];
-       int rps_size[2];
-       int scl_size[2];
-       int cabac_size[2];
-
-       u32 phy_pps;
-       u32 phy_rps;
-       u32 phy_scl;
-       u32 phy_str;
-       u32 phy_yuv;
-       u32 phy_ref;
-       u32 phy_cabac;
-
-       volatile u8 *stream_buf;
-       volatile u8 *pps_buf;
-       volatile u8 *rps_buf;
-       volatile u8 *scl_buf;
-       volatile u8 *yuv_buf;
-       volatile u8 *cabac_buf;
-       volatile u8 *ref_buf;
-
-       u8 *pps;
-       u8 *yuv[2];
-       int i;
-
-       pps_tbl[0] = pps_00;
-       pps_tbl[1] = pps_01;
-
-       register_tbl[0] = register_00;
-       register_tbl[1] = register_01;
-
-       rps_tbl[0] = rps_00;
-       rps_tbl[1] = rps_01;
-
-       scaling_list_tbl[0] = scaling_list_00;
-       scaling_list_tbl[1] = scaling_list_01;
-
-       stream_tbl[0] = stream_00;
-       stream_tbl[1] = stream_01;
-
-       stream_size[0] = sizeof(stream_00);
-       stream_size[1] = sizeof(stream_01);
-
-       pps_size[0] = sizeof(pps_00);
-       pps_size[1] = sizeof(pps_01);
-
-       rps_size[0] = sizeof(rps_00);
-       rps_size[1] = sizeof(rps_01);
-
-       scl_size[0] = sizeof(scaling_list_00);
-       scl_size[1] = sizeof(scaling_list_01);
-
-       cabac_size[0] = sizeof(Cabac_table);
-       cabac_size[1] = sizeof(Cabac_table);
-
-       /* create session */
-       session.pid = current->pid;
-       session.type = VPU_DEC;
-       INIT_LIST_HEAD(&session.waiting);
-       INIT_LIST_HEAD(&session.running);
-       INIT_LIST_HEAD(&session.done);
-       INIT_LIST_HEAD(&session.list_session);
-       init_waitqueue_head(&session.wait);
-       atomic_set(&session.task_running, 0);
-       list_add_tail(&session.list_session, &pservice->session);
-
-       yuv[0] = get_align_ptr_no_copy(256*256*2, &phy_yuv);
-       yuv[1] = get_align_ptr_no_copy(256*256*2, &phy_ref);
-
-       while (testidx < TEST_CNT) {
-               /* create registers */
-               reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);
-               if (NULL == reg) {
-                       vpu_err("error: kmalloc fail in reg_init\n");
-                       return -1;
-               }
-
-               if (size > pservice->reg_size) {
-                       printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);
-                       size = pservice->reg_size;
-               }
-               reg->session = &session;
-               reg->type = session.type;
-               reg->size = size;
-               reg->freq = VPU_FREQ_DEFAULT;
-               reg->reg = (unsigned long *)&reg[1];
-               INIT_LIST_HEAD(&reg->session_link);
-               INIT_LIST_HEAD(&reg->status_link);
-
-               /* TODO: stuff registers */
-               memcpy(&reg->reg[0], register_tbl[testidx], /*sizeof(register_00)*/ 176);
-
-               stream_buf = get_align_ptr(stream_tbl[testidx], stream_size[testidx], &phy_str);
-               pps_buf = get_align_ptr(pps_tbl[0], pps_size[0], &phy_pps);
-               rps_buf = get_align_ptr(rps_tbl[testidx], rps_size[testidx], &phy_rps);
-               scl_buf = get_align_ptr(scaling_list_tbl[testidx], scl_size[testidx], &phy_scl);
-               cabac_buf = get_align_ptr(Cabac_table, cabac_size[testidx], &phy_cabac);
-
-               pps = pps_buf;
-
-               /* TODO: replace reigster address */
-               for (i=0; i<64; i++) {
-                       u32 scaling_offset;
-                       u32 tmp;
-
-                       scaling_offset = (u32)pps[i*80+74];
-                       scaling_offset += (u32)pps[i*80+75] << 8;
-                       scaling_offset += (u32)pps[i*80+76] << 16;
-                       scaling_offset += (u32)pps[i*80+77] << 24;
-
-                       tmp = phy_scl + scaling_offset;
-
-                       pps[i*80+74] = tmp & 0xff;
-                       pps[i*80+75] = (tmp >> 8) & 0xff;
-                       pps[i*80+76] = (tmp >> 16) & 0xff;
-                       pps[i*80+77] = (tmp >> 24) & 0xff;
-               }
-
-               printk("%s %d, phy stream %08x, phy pps %08x, phy rps %08x\n",
-                       __func__, __LINE__, phy_str, phy_pps, phy_rps);
-
-               reg->reg[1] = 0x21;
-               reg->reg[4] = phy_str;
-               reg->reg[5] = ((stream_size[testidx]+15)&(~15))+64;
-               reg->reg[6] = phy_cabac;
-               reg->reg[7] = testidx?phy_ref:phy_yuv;
-               reg->reg[42] = phy_pps;
-               reg->reg[43] = phy_rps;
-               for (i = 10; i <= 24; i++)
-                       reg->reg[i] = phy_yuv;
-
-               mutex_lock(pservice->lock);
-               list_add_tail(&reg->status_link, &pservice->waiting);
-               list_add_tail(&reg->session_link, &session.waiting);
-               mutex_unlock(pservice->lock);
-
-               /* stuff hardware */
-               try_set_reg(data);
-
-               /* wait for result */
-               ret = wait_event_timeout(session.wait, !list_empty(&session.done), VPU_TIMEOUT_DELAY);
-               if (!list_empty(&session.done)) {
-                       if (ret < 0)
-                               vpu_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session.pid, ret);
-                       ret = 0;
-               } else {
-                       if (unlikely(ret < 0)) {
-                               vpu_err("error: pid %d wait task ret %d\n", session.pid, ret);
-                       } else if (0 == ret) {
-                               vpu_err("error: pid %d wait %d task done timeout\n", session.pid, atomic_read(&session.task_running));
-                               ret = -ETIMEDOUT;
-                       }
-               }
-               if (ret < 0) {
-                       int task_running = atomic_read(&session.task_running);
-                       int n;
-                       mutex_lock(pservice->lock);
-                       vpu_service_dump(pservice);
-                       if (task_running) {
-                               atomic_set(&session.task_running, 0);
-                               atomic_sub(task_running, &pservice->total_running);
-                               printk("%d task is running but not return, reset hardware...", task_running);
-                               vpu_reset(data);
-                               printk("done\n");
-                       }
-                       vpu_service_session_clear(pservice, &session);
-                       mutex_unlock(pservice->lock);
-
-                       printk("\nDEC Registers:\n");
-                       n = data->dec_dev.iosize >> 2;
-                       for (i=0; i<n; i++)
-                               printk("\tswreg%d = %08X\n", i, readl(data->dec_dev.hwregs + i));
-
-                       vpu_err("test index %d failed\n", testidx);
-                       break;
-               } else {
-                       vpu_debug(DEBUG_EXTRA_INFO, "test index %d success\n", testidx);
-
-                       vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link);
-
-                       for (i=0; i<68; i++) {
-                               if (i % 4 == 0)
-                                       printk("%02d: ", i);
-                               printk("%08x ", reg->reg[i]);
-                               if ((i+1) % 4 == 0)
-                                       printk("\n");
-                       }
-
-                       testidx++;
-               }
-
-               reg_deinit(data, reg);
-       }
-
-       return 0;
-}
-
-#endif
-
diff --git a/arch/arm/mach-rockchip/vcodec_service.h b/arch/arm/mach-rockchip/vcodec_service.h
deleted file mode 100644 (file)
index 70fa21f..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-\r
-/* arch/arm/mach-rk29/include/mach/vpu_service.h\r
- *\r
- * Copyright (C) 2010 ROCKCHIP, Inc.\r
- * author: chenhengming chm@rock-chips.com\r
- *\r
- * This software is licensed under the terms of the GNU General Public\r
- * License version 2, as published by the Free Software Foundation, and\r
- * may be copied, distributed, and modified under those terms.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- */\r
-\r
-#ifndef __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H\r
-#define __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H\r
-\r
-#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */\r
-\r
-/*\r
- * Ioctl definitions\r
- */\r
-\r
-/* Use 'k' as magic number */\r
-#define VPU_IOC_MAGIC                       'l'\r
-\r
-#define VPU_IOC_SET_CLIENT_TYPE             _IOW(VPU_IOC_MAGIC, 1, unsigned long)\r
-#define VPU_IOC_GET_HW_FUSE_STATUS          _IOW(VPU_IOC_MAGIC, 2, unsigned long)\r
-\r
-#define VPU_IOC_SET_REG                     _IOW(VPU_IOC_MAGIC, 3, unsigned long)\r
-#define VPU_IOC_GET_REG                     _IOW(VPU_IOC_MAGIC, 4, unsigned long)\r
-\r
-#define VPU_IOC_PROBE_IOMMU_STATUS          _IOR(VPU_IOC_MAGIC, 5, unsigned long)\r
-\r
-#ifdef CONFIG_COMPAT\r
-#define COMPAT_VPU_IOC_SET_CLIENT_TYPE       _IOW(VPU_IOC_MAGIC, 1, u32)\r
-#define COMPAT_VPU_IOC_GET_HW_FUSE_STATUS    _IOW(VPU_IOC_MAGIC, 2, u32)\r
-\r
-#define COMPAT_VPU_IOC_SET_REG               _IOW(VPU_IOC_MAGIC, 3, u32)\r
-#define COMPAT_VPU_IOC_GET_REG               _IOW(VPU_IOC_MAGIC, 4, u32)\r
-\r
-#define COMPAT_VPU_IOC_PROBE_IOMMU_STATUS    _IOR(VPU_IOC_MAGIC, 5, u32)\r
-#endif\r
-\r
-enum VPU_CLIENT_TYPE {\r
-       VPU_ENC                 = 0x0,\r
-       VPU_DEC                 = 0x1,\r
-       VPU_PP                  = 0x2,\r
-       VPU_DEC_PP              = 0x3,\r
-       VPU_TYPE_BUTT           ,\r
-};\r
-\r
-/* Hardware decoder configuration description */\r
-\r
-struct vpu_dec_config {\r
-       u32 maxDecPicWidth;         /* Maximum video decoding width supported  */\r
-       u32 maxPpOutPicWidth;       /* Maximum output width of Post-Processor */\r
-       u32 h264_support;            /* HW supports h.264 */\r
-       u32 jpegSupport;            /* HW supports JPEG */\r
-       u32 mpeg4Support;           /* HW supports MPEG-4 */\r
-       u32 customMpeg4Support;     /* HW supports custom MPEG-4 features */\r
-       u32 vc1Support;             /* HW supports VC-1 Simple */\r
-       u32 mpeg2Support;           /* HW supports MPEG-2 */\r
-       u32 ppSupport;              /* HW supports post-processor */\r
-       u32 ppConfig;               /* HW post-processor functions bitmask */\r
-       u32 sorensonSparkSupport;   /* HW supports Sorenson Spark */\r
-       u32 refBufSupport;          /* HW supports reference picture buffering */\r
-       u32 vp6Support;             /* HW supports VP6 */\r
-       u32 vp7Support;             /* HW supports VP7 */\r
-       u32 vp8Support;             /* HW supports VP8 */\r
-       u32 avsSupport;             /* HW supports AVS */\r
-       u32 jpegESupport;           /* HW supports JPEG extensions */\r
-       u32 rvSupport;              /* HW supports REAL */\r
-       u32 mvcSupport;             /* HW supports H264 MVC extension */\r
-};\r
-\r
-/* Hardware encoder configuration description */\r
-\r
-struct vpu_enc_config {\r
-       u32 maxEncodedWidth;        /* Maximum supported width for video encoding (not JPEG) */\r
-       u32 h264Enabled;            /* HW supports H.264 */\r
-       u32 jpegEnabled;            /* HW supports JPEG */\r
-       u32 mpeg4Enabled;           /* HW supports MPEG-4 */\r
-       u32 vsEnabled;              /* HW supports video stabilization */\r
-       u32 rgbEnabled;             /* HW supports RGB input */\r
-       u32 reg_size;\r
-       u32 reserv[2];              /* reverved */\r
-};\r
-\r
-union vpu_config {\r
-       struct vpu_dec_config vpu_dec_conf;\r
-       struct vpu_enc_config vpu_enc_conf;\r
-};\r
-\r
-struct VPUHwCfgReq_t {\r
-       u32 *cfg;\r
-       u32 size;\r
-};\r
-\r
-#define DWL_MPEG2_E         31  /* 1 bit */\r
-#define DWL_VC1_E           29  /* 2 bits */\r
-#define DWL_JPEG_E          28  /* 1 bit */\r
-#define DWL_MPEG4_E         26  /* 2 bits */\r
-#define DWL_H264_E          24  /* 2 bits */\r
-#define DWL_VP6_E           23  /* 1 bit */\r
-#define DWL_PJPEG_E         22  /* 1 bit */\r
-#define DWL_REF_BUFF_E      20  /* 1 bit */\r
-\r
-#define DWL_JPEG_EXT_E          31  /* 1 bit */\r
-#define DWL_REF_BUFF_ILACE_E    30  /* 1 bit */\r
-#define DWL_MPEG4_CUSTOM_E      29  /* 1 bit */\r
-#define DWL_REF_BUFF_DOUBLE_E   28  /* 1 bit */\r
-#define DWL_RV_E            26  /* 2 bits */\r
-#define DWL_VP7_E           24  /* 1 bit */\r
-#define DWL_VP8_E           23  /* 1 bit */\r
-#define DWL_AVS_E           22  /* 1 bit */\r
-#define DWL_MVC_E           20  /* 2 bits */\r
-\r
-#define DWL_CFG_E           24  /* 4 bits */\r
-#define DWL_PP_E            16  /* 1 bit */\r
-\r
-#define DWL_SORENSONSPARK_E 11  /* 1 bit */\r
-\r
-#define DWL_H264_FUSE_E          31 /* 1 bit */\r
-#define DWL_MPEG4_FUSE_E         30 /* 1 bit */\r
-#define DWL_MPEG2_FUSE_E         29 /* 1 bit */\r
-#define DWL_SORENSONSPARK_FUSE_E 28 /* 1 bit */\r
-#define DWL_JPEG_FUSE_E          27 /* 1 bit */\r
-#define DWL_VP6_FUSE_E           26 /* 1 bit */\r
-#define DWL_VC1_FUSE_E           25 /* 1 bit */\r
-#define DWL_PJPEG_FUSE_E         24 /* 1 bit */\r
-#define DWL_CUSTOM_MPEG4_FUSE_E  23 /* 1 bit */\r
-#define DWL_RV_FUSE_E            22 /* 1 bit */\r
-#define DWL_VP7_FUSE_E           21 /* 1 bit */\r
-#define DWL_VP8_FUSE_E           20 /* 1 bit */\r
-#define DWL_AVS_FUSE_E           19 /* 1 bit */\r
-#define DWL_MVC_FUSE_E           18 /* 1 bit */\r
-\r
-#define DWL_DEC_MAX_1920_FUSE_E  15 /* 1 bit */\r
-#define DWL_DEC_MAX_1280_FUSE_E  14 /* 1 bit */\r
-#define DWL_DEC_MAX_720_FUSE_E   13 /* 1 bit */\r
-#define DWL_DEC_MAX_352_FUSE_E   12 /* 1 bit */\r
-#define DWL_REF_BUFF_FUSE_E       7 /* 1 bit */\r
-\r
-\r
-#define DWL_PP_FUSE_E    31  /* 1 bit */\r
-#define DWL_PP_DEINTERLACE_FUSE_E   30  /* 1 bit */\r
-#define DWL_PP_ALPHA_BLEND_FUSE_E   29  /* 1 bit */\r
-#define DWL_PP_MAX_1920_FUSE_E  15  /* 1 bit */\r
-#define DWL_PP_MAX_1280_FUSE_E  14  /* 1 bit */\r
-#define DWL_PP_MAX_720_FUSE_E  13  /* 1 bit */\r
-#define DWL_PP_MAX_352_FUSE_E  12  /* 1 bit */\r
-\r
-\r
-#define MPEG4_NOT_SUPPORTED             (u32)(0x00)\r
-#define MPEG4_SIMPLE_PROFILE            (u32)(0x01)\r
-#define MPEG4_ADVANCED_SIMPLE_PROFILE   (u32)(0x02)\r
-#define MPEG4_CUSTOM_NOT_SUPPORTED      (u32)(0x00)\r
-#define MPEG4_CUSTOM_FEATURE_1          (u32)(0x01)\r
-#define H264_NOT_SUPPORTED              (u32)(0x00)\r
-#define H264_BASELINE_PROFILE           (u32)(0x01)\r
-#define H264_MAIN_PROFILE               (u32)(0x02)\r
-#define H264_HIGH_PROFILE               (u32)(0x03)\r
-#define VC1_NOT_SUPPORTED               (u32)(0x00)\r
-#define VC1_SIMPLE_PROFILE              (u32)(0x01)\r
-#define VC1_MAIN_PROFILE                (u32)(0x02)\r
-#define VC1_ADVANCED_PROFILE            (u32)(0x03)\r
-#define MPEG2_NOT_SUPPORTED             (u32)(0x00)\r
-#define MPEG2_MAIN_PROFILE              (u32)(0x01)\r
-#define JPEG_NOT_SUPPORTED              (u32)(0x00)\r
-#define JPEG_BASELINE                   (u32)(0x01)\r
-#define JPEG_PROGRESSIVE                (u32)(0x02)\r
-#define PP_NOT_SUPPORTED                (u32)(0x00)\r
-#define PP_SUPPORTED                    (u32)(0x01)\r
-#define PP_DITHERING                    (u32)(0x10000000)\r
-#define PP_SCALING                      (u32)(0x0C000000)\r
-#define PP_DEINTERLACING                (u32)(0x02000000)\r
-#define PP_ALPHA_BLENDING               (u32)(0x01000000)\r
-#define SORENSON_SPARK_NOT_SUPPORTED    (u32)(0x00)\r
-#define SORENSON_SPARK_SUPPORTED        (u32)(0x01)\r
-#define VP6_NOT_SUPPORTED               (u32)(0x00)\r
-#define VP6_SUPPORTED                   (u32)(0x01)\r
-#define VP7_NOT_SUPPORTED               (u32)(0x00)\r
-#define VP7_SUPPORTED                   (u32)(0x01)\r
-#define VP8_NOT_SUPPORTED               (u32)(0x00)\r
-#define VP8_SUPPORTED                   (u32)(0x01)\r
-#define REF_BUF_NOT_SUPPORTED           (u32)(0x00)\r
-#define REF_BUF_SUPPORTED               (u32)(0x01)\r
-#define REF_BUF_INTERLACED              (u32)(0x02)\r
-#define REF_BUF_DOUBLE                  (u32)(0x04)\r
-#define AVS_NOT_SUPPORTED               (u32)(0x00)\r
-#define AVS_SUPPORTED                   (u32)(0x01)\r
-#define JPEG_EXT_NOT_SUPPORTED          (u32)(0x00)\r
-#define JPEG_EXT_SUPPORTED              (u32)(0x01)\r
-#define RV_NOT_SUPPORTED                (u32)(0x00)\r
-#define RV_SUPPORTED                    (u32)(0x01)\r
-#define MVC_NOT_SUPPORTED               (u32)(0x00)\r
-#define MVC_SUPPORTED                   (u32)(0x01)\r
-\r
-#define H264_NOT_SUPPORTED_FUSE             (u32)(0x00)\r
-#define H264_FUSE_ENABLED                   (u32)(0x01)\r
-#define MPEG4_NOT_SUPPORTED_FUSE            (u32)(0x00)\r
-#define MPEG4_FUSE_ENABLED                  (u32)(0x01)\r
-#define MPEG2_NOT_SUPPORTED_FUSE            (u32)(0x00)\r
-#define MPEG2_FUSE_ENABLED                  (u32)(0x01)\r
-#define SORENSON_SPARK_NOT_SUPPORTED_FUSE   (u32)(0x00)\r
-#define SORENSON_SPARK_ENABLED              (u32)(0x01)\r
-#define JPEG_NOT_SUPPORTED_FUSE             (u32)(0x00)\r
-#define JPEG_FUSE_ENABLED                   (u32)(0x01)\r
-#define VP6_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define VP6_FUSE_ENABLED                    (u32)(0x01)\r
-#define VP7_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define VP7_FUSE_ENABLED                    (u32)(0x01)\r
-#define VP8_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define VP8_FUSE_ENABLED                    (u32)(0x01)\r
-#define VC1_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define VC1_FUSE_ENABLED                    (u32)(0x01)\r
-#define JPEG_PROGRESSIVE_NOT_SUPPORTED_FUSE (u32)(0x00)\r
-#define JPEG_PROGRESSIVE_FUSE_ENABLED       (u32)(0x01)\r
-#define REF_BUF_NOT_SUPPORTED_FUSE          (u32)(0x00)\r
-#define REF_BUF_FUSE_ENABLED                (u32)(0x01)\r
-#define AVS_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define AVS_FUSE_ENABLED                    (u32)(0x01)\r
-#define RV_NOT_SUPPORTED_FUSE               (u32)(0x00)\r
-#define RV_FUSE_ENABLED                     (u32)(0x01)\r
-#define MVC_NOT_SUPPORTED_FUSE              (u32)(0x00)\r
-#define MVC_FUSE_ENABLED                    (u32)(0x01)\r
-\r
-#define PP_NOT_SUPPORTED_FUSE               (u32)(0x00)\r
-#define PP_FUSE_ENABLED                     (u32)(0x01)\r
-#define PP_FUSE_DEINTERLACING_ENABLED       (u32)(0x40000000)\r
-#define PP_FUSE_ALPHA_BLENDING_ENABLED      (u32)(0x20000000)\r
-#define MAX_PP_OUT_WIDHT_1920_FUSE_ENABLED  (u32)(0x00008000)\r
-#define MAX_PP_OUT_WIDHT_1280_FUSE_ENABLED  (u32)(0x00004000)\r
-#define MAX_PP_OUT_WIDHT_720_FUSE_ENABLED   (u32)(0x00002000)\r
-#define MAX_PP_OUT_WIDHT_352_FUSE_ENABLED   (u32)(0x00001000)\r
-\r
-#define VPU_DEC_HWCFG0              50\r
-#define VPU_DEC_HWCFG1              51\r
-#define VPU_DEC_HW_FUSE_CFG         57\r
-#define VPU_PP_HW_SYNTH_CFG         40\r
-#define VPU_PP_HW_FUSE_CFG          41\r
-\r
-struct VPUHwFuseStatus_t {\r
-       u32 h264SupportFuse;            /* HW supports h.264 */\r
-       u32 mpeg4SupportFuse;           /* HW supports MPEG-4 */\r
-       u32 mpeg2SupportFuse;           /* HW supports MPEG-2 */\r
-       u32 sorensonSparkSupportFuse;   /* HW supports Sorenson Spark */\r
-       u32 jpegSupportFuse;            /* HW supports JPEG */\r
-       u32 vp6SupportFuse;             /* HW supports VP6 */\r
-       u32 vp7SupportFuse;             /* HW supports VP6 */\r
-       u32 vp8SupportFuse;             /* HW supports VP6 */\r
-       u32 vc1SupportFuse;             /* HW supports VC-1 Simple */\r
-       u32 jpegProgSupportFuse;        /* HW supports Progressive JPEG */\r
-       u32 ppSupportFuse;              /* HW supports post-processor */\r
-       u32 ppConfigFuse;               /* HW post-processor functions bitmask */\r
-       u32 maxDecPicWidthFuse;         /* Maximum video decoding width supported  */\r
-       u32 maxPpOutPicWidthFuse;       /* Maximum output width of Post-Processor */\r
-       u32 refBufSupportFuse;          /* HW supports reference picture buffering */\r
-       u32 avsSupportFuse;             /* one of the AVS values defined above */\r
-       u32 rvSupportFuse;              /* one of the REAL values defined above */\r
-       u32 mvcSupportFuse;\r
-       u32 customMpeg4SupportFuse;     /* Fuse for custom MPEG-4 */\r
-};\r
-\r
-\r
-#endif\r
-\r
index 6034139cacf2ff673de7b4fd1b525a4e9d94bce0..670a5cd121353434bdef62233143f59e5e830ea4 100755 (executable)
@@ -65,6 +65,7 @@ source "drivers/video/rockchip/transmitter/Kconfig"
 source "drivers/video/rockchip/hdmi/Kconfig"
 source "drivers/video/rockchip/tve/Kconfig"
 source "drivers/video/rockchip/rga/Kconfig"
+source "drivers/video/rockchip/vcodec/Kconfig"
 source "drivers/video/rockchip/rga2/Kconfig"
 source "drivers/video/rockchip/iep/Kconfig"
 
index 4d899cbd9a698e84f495901602b48038332d4964..b828e66823f6337e471242d783dcc646e3880ee8 100755 (executable)
@@ -6,5 +6,5 @@ obj-$(CONFIG_FB_ROCKCHIP) += display-sys.o lcdc/
 obj-$(CONFIG_RK_HDMI) += hdmi/
 obj-$(CONFIG_IEP) += iep/
 obj-$(CONFIG_RK_TVENCODER) += tve/
-
+obj-$(CONFIG_RK_VCODEC) += vcodec/
 
diff --git a/drivers/video/rockchip/vcodec/Kconfig b/drivers/video/rockchip/vcodec/Kconfig
new file mode 100644 (file)
index 0000000..149b2df
--- /dev/null
@@ -0,0 +1,9 @@
+menu "VCODEC"
+       depends on ARCH_ROCKCHIP
+
+config RK_VCODEC
+       tristate "VCODEC (VPU HEVC) service driver in kernel"
+       depends on ARCH_ROCKCHIP
+       default n
+
+endmenu
diff --git a/drivers/video/rockchip/vcodec/Makefile b/drivers/video/rockchip/vcodec/Makefile
new file mode 100644 (file)
index 0000000..cf0cdcb
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_RK_VCODEC) += vcodec_service.o
diff --git a/drivers/video/rockchip/vcodec/vcodec_hw_info.h b/drivers/video/rockchip/vcodec/vcodec_hw_info.h
new file mode 100644 (file)
index 0000000..e8de8b1
--- /dev/null
@@ -0,0 +1,227 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: Herman Chen herman.chen@rock-chips.com
+ *         Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_INFO_H
+
+/*
+ * Hardware id is for hardware detection
+ * Driver will read the hardware ID register first, then try to find a mactch
+ * hardware from the enum ID below.
+ */
+enum VPU_HW_ID {
+       VPU_DEC_ID_9190         = 0x6731,
+       VPU_ID_8270             = 0x8270,
+       VPU_ID_4831             = 0x4831,
+       HEVC_ID                 = 0x6867,
+       RKV_DEC_ID              = 0x6876,
+       VPU2_ID                 = 0x0000,
+};
+
+/*
+ * Different hardware has different feature. So we catalogue these features
+ * into three class:
+ *
+ * 1. register io feature determined by hardware type
+ *    including register offset, register file size, etc
+ *
+ * 2. runtime register config feature determined by task type
+ *    including irq / enable / length register, bit mask, etc
+ *
+ * 3. file handle translate feature determined by vcodec format type
+ *    register translation map table
+ *
+ * These three type features composite a complete codec information structure
+ */
+enum HW_TYPE {
+       HW_VPU,
+       HW_VPU2,
+       HW_RKV,
+       HW_TYPE_BUTT,
+};
+
+enum TASK_TYPE {
+       TASK_ENC,
+       TASK_DEC,
+       TASK_PP,
+       TASK_DEC_PP,
+       TASK_TYPE_BUTT,
+};
+
+enum FORMAT_TYPE {
+       FMT_DEC_BASE = 0,
+       FMT_JPEGD = FMT_DEC_BASE,
+
+       FMT_H263D,
+       FMT_H264D,
+       FMT_H265D,
+
+       FMT_MPEG1D,
+       FMT_MPEG2D,
+       FMT_MPEG4D,
+
+       FMT_VP6D,
+       FMT_VP7D,
+       FMT_VP8D,
+       FMT_VP9D,
+
+       FMT_VC1D,
+       FMT_AVSD,
+
+       FMT_DEC_BUTT,
+
+       FMT_PP_BASE = FMT_DEC_BUTT,
+       FMT_PP = FMT_PP_BASE,
+       FMT_PP_BUTT,
+
+       FMT_ENC_BASE = FMT_PP_BUTT,
+       FMT_JPEGE = FMT_ENC_BASE,
+
+       FMT_H264E,
+
+       FMT_VP8E,
+
+       FMT_ENC_BUTT,
+       FMT_TYPE_BUTT = FMT_ENC_BUTT,
+};
+
+/**
+ * struct for hardware task operation
+ */
+struct vpu_hw_info {
+       enum VPU_HW_ID  hw_id;
+       u32             enc_offset;
+       u32             enc_reg_num;
+       u32             enc_io_size;
+
+       u32             dec_offset;
+       u32             dec_reg_num;
+       u32             dec_io_size;
+
+       /*
+        * register range for enc/dec/pp/dec_pp
+        * base/end of dec/pp/dec_pp specify the register range to config
+        */
+       u32             base_dec;
+       u32             base_pp;
+       u32             base_dec_pp;
+       u32             end_dec;
+       u32             end_pp;
+       u32             end_dec_pp;
+};
+
+struct vpu_task_info {
+       char *name;
+       struct timeval start;
+       struct timeval end;
+
+       /*
+        * task enable register
+        * use for enable hardware task process
+        *  -1 for invalid
+        */
+       int reg_en;
+
+       /* register of task auto gating, alway valid */
+       int reg_gating;
+
+       /* register of task irq, alway valid */
+       int reg_irq;
+
+       /*
+        * stream length register
+        * only valid for decoder task
+        * -1 for invalid (encoder)
+        */
+       int reg_len;
+
+       /*
+        * direct mv register
+        * special offset scale, offset multiply by 16
+        *
+        * valid on vpu & vpu2
+        * -1 for invalid
+        */
+       int reg_dir_mv;
+
+       /*
+        * pps register
+        * special register for scaling list address process
+        *
+        * valid on rkv
+        * -1 for invalid
+        */
+       int reg_pps;
+
+       /*
+        * decoder pipeline mode register
+        *
+        * valid on vpu & vpu2
+        * -1 for invalid
+        */
+       int reg_pipe;
+
+       /* task enable bit mask for enable register */
+       u32 enable_mask;
+
+       /* task auto gating mask for enable register */
+       u32 gating_mask;
+
+       /* task pipeline mode mask for pipe register */
+       u32 pipe_mask;
+
+       /* task inturrpt bit mask for irq register */
+       u32 irq_mask;
+
+       /* task ready bit mask for irq register */
+       u32 ready_mask;
+
+       /* task error bit mask for irq register */
+       u32 error_mask;
+
+       enum FORMAT_TYPE (*get_fmt)(u32 *regs);
+};
+
+struct vpu_trans_info {
+       const int count;
+       const char * const table;
+};
+
+struct vcodec_info {
+       enum VPU_HW_ID                  hw_id;
+       struct vpu_hw_info              *hw_info;
+       struct vpu_task_info            *task_info;
+       const struct vpu_trans_info     *trans_info;
+};
+
+#define DEF_FMT_TRANS_TBL(fmt, args...) \
+       static const char trans_tbl_##fmt[] = { \
+               args \
+       }
+
+#define SETUP_FMT_TBL(id, fmt) \
+       [id] = { \
+               .count = sizeof(trans_tbl_##fmt), \
+               .table = trans_tbl_##fmt, \
+       }
+
+#define EMPTY_FMT_TBL(id) \
+       [id] = { \
+               .count = 0, \
+               .table = NULL, \
+       }
+
+#endif
diff --git a/drivers/video/rockchip/vcodec/vcodec_hw_rkv.h b/drivers/video/rockchip/vcodec/vcodec_hw_rkv.h
new file mode 100644 (file)
index 0000000..27e1adc
--- /dev/null
@@ -0,0 +1,226 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ *        Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_RKV_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_HEVC_DEC               (68)
+#define REG_NUM_RKV_DEC                        (78)
+
+/* enable and gating register */
+#define RKV_REG_EN_DEC                 1
+#define RKV_REG_DEC_GATING_BIT         BIT(1)
+
+/* interrupt and error status register */
+#define HEVC_INTERRUPT_REGISTER                1
+#define HEVC_INTERRUPT_BIT             BIT(8)
+#define HEVC_DEC_INT_RAW_BIT           BIT(9)
+#define HEVC_READY_BIT                 BIT(12)
+#define HEVC_DEC_BUS_ERROR_BIT         BIT(13)
+#define HEVC_DEC_STR_ERROR_BIT         BIT(14)
+#define HEVC_DEC_TIMEOUT_BIT           BIT(15)
+#define HEVC_DEC_BUFFER_EMPTY_BIT      BIT(16)
+#define HEVC_DEC_COLMV_ERROR_BIT       BIT(17)
+#define HEVC_DEC_ERR_MASK              (HEVC_DEC_BUS_ERROR_BIT \
+                                       |HEVC_DEC_STR_ERROR_BIT \
+                                       |HEVC_DEC_TIMEOUT_BIT \
+                                       |HEVC_DEC_BUFFER_EMPTY_BIT \
+                                       |HEVC_DEC_COLMV_ERROR_BIT)
+
+#define RKV_DEC_INTERRUPT_REGISTER     1
+#define RKV_DEC_INTERRUPT_BIT          BIT(8)
+#define RKV_DEC_INT_RAW_BIT            BIT(9)
+#define RKV_DEC_READY_BIT              BIT(12)
+#define RKV_DEC_BUS_ERROR_BIT          BIT(13)
+#define RKV_DEC_STR_ERROR_BIT          BIT(14)
+#define RKV_DEC_TIMEOUT_BIT            BIT(15)
+#define RKV_DEC_BUFFER_EMPTY_BIT       BIT(16)
+#define RKV_DEC_COLMV_ERROR_BIT                BIT(17)
+#define RKV_DEC_ERR_MASK               (RKV_DEC_BUS_ERROR_BIT \
+                                       |RKV_DEC_STR_ERROR_BIT \
+                                       |RKV_DEC_TIMEOUT_BIT \
+                                       |RKV_DEC_BUFFER_EMPTY_BIT \
+                                       |RKV_DEC_COLMV_ERROR_BIT)
+
+static const enum FORMAT_TYPE rkv_dec_fmt_tbl[] = {
+       [0]  = FMT_H265D,
+       [1]  = FMT_H264D,
+       [2]  = FMT_VP9D,
+       [3]  = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE rkv_dec_get_fmt(u32 *regs)
+{
+       u32 fmt_id = (regs[2] >> 20) & 0x3;
+       enum FORMAT_TYPE type = rkv_dec_fmt_tbl[fmt_id];
+       return type;
+}
+
+static struct vpu_task_info task_rkv[TASK_TYPE_BUTT] = {
+       {
+               .name = "invalid",
+               .reg_en = 0,
+               .reg_irq = 0,
+               .reg_len = 0,
+               .reg_dir_mv = 0,
+               .reg_pps = 0,
+               .reg_pipe = 0,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = 0,
+               .irq_mask = 0,
+               .ready_mask = 0,
+               .error_mask = 0,
+               .get_fmt = NULL,
+       },
+       {
+               .name = "rkvdec",
+               .reg_en = RKV_REG_EN_DEC,
+               .reg_irq = RKV_DEC_INTERRUPT_REGISTER,
+               .reg_len = 4,
+               .reg_dir_mv = 52,
+               .reg_pps = 42,
+               .reg_pipe = 0,
+               .enable_mask = 0,
+               .gating_mask = RKV_REG_DEC_GATING_BIT,
+               .irq_mask = HEVC_INTERRUPT_BIT,
+               .pipe_mask = 0,
+               .ready_mask = HEVC_READY_BIT,
+               .error_mask = HEVC_DEC_ERR_MASK,
+               .get_fmt = rkv_dec_get_fmt,
+       },
+       {
+               .name = "invalid",
+               .reg_en = 0,
+               .reg_irq = 0,
+               .reg_len = 0,
+               .reg_dir_mv = 0,
+               .reg_pps = 0,
+               .reg_pipe = 0,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = 0,
+               .irq_mask = 0,
+               .ready_mask = 0,
+               .error_mask = 0,
+               .get_fmt = NULL,
+       },
+       {
+               .name = "invalid",
+               .reg_en = 0,
+               .reg_irq = 0,
+               .reg_len = 0,
+               .reg_dir_mv = 0,
+               .reg_pps = 0,
+               .reg_pipe = 0,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = 0,
+               .irq_mask = 0,
+               .ready_mask = 0,
+               .error_mask = 0,
+               .get_fmt = NULL,
+       },};
+
+static struct vpu_hw_info hw_rkhevc = {
+       .hw_id          = HEVC_ID,
+
+       .enc_offset     = 0,
+       .enc_reg_num    = 0,
+       .enc_io_size    = 0,
+
+       .dec_offset     = 0,
+       .dec_reg_num    = REG_NUM_HEVC_DEC,
+       .dec_io_size    = REG_NUM_HEVC_DEC * 4,
+
+       /* NOTE: can not write to register 0 */
+       .base_dec       = 1,
+       .base_pp        = 0,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_HEVC_DEC,
+       .end_pp         = 0,
+       .end_dec_pp     = 0,
+};
+
+static struct vpu_hw_info hw_rkvdec = {
+       .hw_id          = RKV_DEC_ID,
+
+       .enc_offset     = 0,
+       .enc_reg_num    = 0,
+       .enc_io_size    = 0,
+
+       .dec_offset     = 0x0,
+       .dec_reg_num    = REG_NUM_RKV_DEC,
+       .dec_io_size    = REG_NUM_RKV_DEC * 4,
+
+       /* NOTE: can not write to register 0 */
+       .base_dec       = 1,
+       .base_pp        = 0,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_RKV_DEC,
+       .end_pp         = 0,
+       .end_dec_pp     = 0,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(rkv_h264d,
+                 4,  6,  7,  10, 11, 12, 13, 14,
+                 15, 16, 17, 18, 19, 20, 21, 22,
+                 23, 24, 41, 42, 43, 48, 75
+);
+
+DEF_FMT_TRANS_TBL(rkv_h265d,
+                 4,  6,  7,  10, 11, 12, 13, 14,
+                 15, 16, 17, 18, 19, 20, 21, 22,
+                 23, 24, 42, 43
+);
+
+DEF_FMT_TRANS_TBL(rkv_vp9d,
+                 4,  6,  7,  11, 12, 13, 14, 15,
+                 16, 52
+);
+
+const struct vpu_trans_info trans_rkv[FMT_TYPE_BUTT] = {
+       EMPTY_FMT_TBL(FMT_JPEGD),
+       EMPTY_FMT_TBL(FMT_H263D),
+       SETUP_FMT_TBL(FMT_H264D , rkv_h264d),
+       SETUP_FMT_TBL(FMT_H265D , rkv_h265d),
+
+       EMPTY_FMT_TBL(FMT_MPEG1D),
+       EMPTY_FMT_TBL(FMT_MPEG2D),
+       EMPTY_FMT_TBL(FMT_MPEG4D),
+
+       EMPTY_FMT_TBL(FMT_VP6D),
+       EMPTY_FMT_TBL(FMT_VP7D),
+       EMPTY_FMT_TBL(FMT_VP8D),
+       SETUP_FMT_TBL(FMT_VP9D  , rkv_vp9d),
+
+       EMPTY_FMT_TBL(FMT_PP),
+
+       EMPTY_FMT_TBL(FMT_VC1D),
+       EMPTY_FMT_TBL(FMT_AVSD),
+
+       EMPTY_FMT_TBL(FMT_JPEGE),
+       EMPTY_FMT_TBL(FMT_H264E),
+       EMPTY_FMT_TBL(FMT_VP8E),
+};
+
+#endif
diff --git a/drivers/video/rockchip/vcodec/vcodec_hw_vpu.h b/drivers/video/rockchip/vcodec/vcodec_hw_vpu.h
new file mode 100644 (file)
index 0000000..3b8201a
--- /dev/null
@@ -0,0 +1,318 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ *        Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_9190_DEC               (60)
+#define REG_NUM_9190_PP                        (41)
+#define REG_NUM_9190_DEC_PP            (REG_NUM_9190_DEC + REG_NUM_9190_PP)
+
+#define REG_NUM_DEC_PP                 (REG_NUM_9190_DEC + REG_NUM_9190_PP)
+
+#define REG_NUM_ENC_8270               (96)
+#define REG_SIZE_ENC_8270              (0x200)
+#define REG_NUM_ENC_4831               (164)
+#define REG_SIZE_ENC_4831              (0x400)
+
+
+/* enable and gating register */
+#define VPU_REG_EN_ENC                 14
+#define VPU_REG_ENC_GATE               2
+#define VPU_REG_ENC_GATE_BIT           BIT(4)
+
+#define VPU_REG_EN_DEC                 1
+#define VPU_REG_DEC_GATE               2
+#define VPU_REG_DEC_GATE_BIT           BIT(10)
+#define VPU_REG_EN_PP                  0
+#define VPU_REG_PP_GATE                        1
+#define VPU_REG_PP_GATE_BIT            BIT(8)
+#define VPU_REG_EN_DEC_PP              1
+#define VPU_REG_DEC_PP_GATE            61
+#define VPU_REG_DEC_PP_GATE_BIT                BIT(8)
+
+/* interrupt and error status register */
+#define VPU_DEC_INTERRUPT_REGISTER      1
+#define VPU_DEC_INTERRUPT_BIT          BIT(8)
+#define VPU_DEC_READY_BIT              BIT(12)
+#define VPU_DEC_BUS_ERROR_BIT          BIT(13)
+#define VPU_DEC_BUFFER_EMPTY_BIT       BIT(14)
+#define VPU_DEC_ASO_ERROR_BIT          BIT(15)
+#define VPU_DEC_STREAM_ERROR_BIT       BIT(16)
+#define VPU_DEC_SLICE_DONE_BIT         BIT(17)
+#define VPU_DEC_TIMEOUT_BIT            BIT(18)
+#define VPU_DEC_ERR_MASK               (VPU_DEC_BUS_ERROR_BIT \
+                                       |VPU_DEC_BUFFER_EMPTY_BIT \
+                                       |VPU_DEC_STREAM_ERROR_BIT \
+                                       |VPU_DEC_TIMEOUT_BIT)
+
+#define VPU_PP_INTERRUPT_REGISTER      60
+#define VPU_PP_PIPELINE_MODE_BIT       BIT(1)
+#define VPU_PP_INTERRUPT_BIT           BIT(8)
+#define VPU_PP_READY_BIT               BIT(12)
+#define VPU_PP_BUS_ERROR_BIT           BIT(13)
+#define VPU_PP_ERR_MASK                        VPU_PP_BUS_ERROR_BIT
+
+#define VPU_ENC_INTERRUPT_REGISTER     1
+#define VPU_ENC_INTERRUPT_BIT          BIT(0)
+#define VPU_ENC_READY_BIT              BIT(2)
+#define VPU_ENC_BUS_ERROR_BIT          BIT(3)
+#define VPU_ENC_BUFFER_FULL_BIT                BIT(5)
+#define VPU_ENC_TIMEOUT_BIT            BIT(6)
+#define VPU_ENC_ERR_MASK               (VPU_ENC_BUS_ERROR_BIT \
+                                       |VPU_ENC_BUFFER_FULL_BIT \
+                                       |VPU_ENC_TIMEOUT_BIT)
+
+static const enum FORMAT_TYPE vpu_dec_fmt_tbl[] = {
+       [0]  = FMT_H264D,
+       [1]  = FMT_MPEG4D,
+       [2]  = FMT_H263D,
+       [3]  = FMT_JPEGD,
+       [4]  = FMT_VC1D,
+       [5]  = FMT_MPEG2D,
+       [6]  = FMT_MPEG1D,
+       [7]  = FMT_VP6D,
+       [8]  = FMT_TYPE_BUTT,
+       [9]  = FMT_VP7D,
+       [10] = FMT_VP8D,
+       [11] = FMT_AVSD,
+       [12] = FMT_TYPE_BUTT,
+       [13] = FMT_TYPE_BUTT,
+       [14] = FMT_TYPE_BUTT,
+       [15] = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE vpu_dec_get_fmt(u32 *regs)
+{
+       u32 fmt_id = (regs[3] >> 28) & 0xf;
+       enum FORMAT_TYPE type = vpu_dec_fmt_tbl[fmt_id];
+       return type;
+}
+
+static enum FORMAT_TYPE vpu_pp_get_fmt(u32 *regs)
+{
+       return FMT_PP;
+}
+
+static const enum FORMAT_TYPE vpu_enc_fmt_tbl[] = {
+       [0]  = FMT_TYPE_BUTT,
+       [1]  = FMT_VP8E,
+       [2]  = FMT_JPEGE,
+       [3]  = FMT_H264E,
+};
+
+static enum FORMAT_TYPE vpu_enc_get_fmt(u32 *regs)
+{
+       u32 fmt_id = (regs[VPU_REG_EN_ENC] >> 1) & 0x3;
+       enum FORMAT_TYPE type = vpu_enc_fmt_tbl[fmt_id];
+       return type;
+}
+
+static struct vpu_task_info task_vpu[TASK_TYPE_BUTT] = {
+       {
+               .name = "vpu_enc",
+               .reg_en = VPU_REG_EN_ENC,
+               .reg_irq = VPU_ENC_INTERRUPT_REGISTER,
+               .reg_len = -1,
+               .reg_dir_mv = -1,
+               .reg_pps = -1,
+               .reg_pipe = -1,
+               .enable_mask = 0x6,
+               .gating_mask = 0,
+               .pipe_mask = 0,
+               .irq_mask = VPU_ENC_INTERRUPT_BIT,
+               .ready_mask = VPU_ENC_READY_BIT,
+               .error_mask = VPU_ENC_ERR_MASK,
+               .get_fmt = vpu_enc_get_fmt,
+       },
+       {
+               .name = "vpu_dec",
+               .reg_en = VPU_REG_EN_DEC,
+               .reg_irq = VPU_DEC_INTERRUPT_REGISTER,
+               .reg_len = 12,
+               .reg_dir_mv = 41,
+               .reg_pps = -1,
+               .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU_DEC_INTERRUPT_BIT,
+               .ready_mask = VPU_DEC_READY_BIT,
+               .error_mask = VPU_DEC_ERR_MASK,
+               .get_fmt = vpu_dec_get_fmt,
+       },
+       {
+               .name = "vpu_pp",
+               .reg_en = VPU_REG_EN_PP,
+               .reg_irq = VPU_PP_INTERRUPT_REGISTER,
+               .reg_len = -1,
+               .reg_dir_mv = -1,
+               .reg_pps = -1,
+               .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU_PP_INTERRUPT_BIT,
+               .ready_mask = VPU_PP_READY_BIT,
+               .error_mask = VPU_PP_ERR_MASK,
+               .get_fmt = vpu_pp_get_fmt,
+       },
+       {
+               .name = "vpu_dec_pp",
+               .reg_en = VPU_REG_EN_DEC,
+               .reg_irq = VPU_DEC_INTERRUPT_REGISTER,
+               .reg_len = 12,
+               .reg_dir_mv = 41,
+               .reg_pps = -1,
+               .reg_pipe = VPU_PP_INTERRUPT_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = 0,
+               .pipe_mask = VPU_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU_DEC_INTERRUPT_BIT,
+               .ready_mask = VPU_DEC_READY_BIT,
+               .error_mask = VPU_DEC_ERR_MASK,
+               .get_fmt = vpu_dec_get_fmt,
+       },
+};
+
+static struct vpu_hw_info hw_vpu_8270 = {
+       .hw_id          = VPU_ID_8270,
+
+       .enc_offset     = 0x0,
+       .enc_reg_num    = REG_NUM_ENC_8270,
+       .enc_io_size    = REG_NUM_ENC_8270 * 4,
+
+       .dec_offset     = REG_SIZE_ENC_8270,
+       .dec_reg_num    = REG_NUM_9190_DEC_PP,
+       .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
+
+       .base_dec       = 0,
+       .base_pp        = VPU_PP_INTERRUPT_REGISTER,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_9190_DEC,
+       .end_pp         = REG_NUM_9190_DEC_PP,
+       .end_dec_pp     = REG_NUM_9190_DEC_PP,
+};
+
+static struct vpu_hw_info hw_vpu_4831 = {
+       .hw_id          = VPU_ID_4831,
+
+       .enc_offset     = 0x0,
+       .enc_reg_num    = REG_NUM_ENC_4831,
+       .enc_io_size    = REG_NUM_ENC_4831 * 4,
+
+       .dec_offset     = REG_SIZE_ENC_4831,
+       .dec_reg_num    = REG_NUM_9190_DEC_PP,
+       .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
+
+       .base_dec       = 0,
+       .base_pp        = VPU_PP_INTERRUPT_REGISTER,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_9190_DEC,
+       .end_pp         = REG_NUM_9190_DEC_PP,
+       .end_dec_pp     = REG_NUM_9190_DEC_PP,
+};
+
+static struct vpu_hw_info hw_vpu_9190 = {
+       .hw_id          = VPU_DEC_ID_9190,
+
+       .enc_offset     = 0x0,
+       .enc_reg_num    = 0,
+       .enc_io_size    = 0,
+
+       .dec_offset     = 0,
+       .dec_reg_num    = REG_NUM_9190_DEC_PP,
+       .dec_io_size    = REG_NUM_9190_DEC_PP * 4,
+
+       .base_dec       = 0,
+       .base_pp        = VPU_PP_INTERRUPT_REGISTER,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_9190_DEC,
+       .end_pp         = REG_NUM_9190_DEC_PP,
+       .end_dec_pp     = REG_NUM_9190_DEC_PP,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(vpu_jpegd,
+                 12, 40, 66, 67
+);
+
+DEF_FMT_TRANS_TBL(vpu_h264d,
+                 12, 13, 14, 15, 16, 17, 18, 19,
+                 20, 21, 22, 23, 24, 25, 26, 27,
+                 28, 29, 40, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp6d,
+                 12, 13, 14, 18, 27, 40
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp8d,
+                 10, 12, 13, 14, 18, 19, 22, 23,
+                 24, 25, 26, 27, 28, 29, 40
+);
+
+DEF_FMT_TRANS_TBL(vpu_vc1d,
+                 12, 13, 14, 15, 16, 17, 27, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_defaultd,
+                 12, 13, 14, 15, 16, 17, 40, 41
+);
+
+DEF_FMT_TRANS_TBL(vpu_default_pp,
+                 63, 64, 65, 66, 67, 73, 74
+);
+
+DEF_FMT_TRANS_TBL(vpu_vp8e,
+                 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 26, 51, 52, 58, 59
+);
+
+DEF_FMT_TRANS_TBL(vpu_defaulte,
+                 5, 6, 7, 8, 9, 10, 11, 12, 13, 51
+);
+
+const struct vpu_trans_info trans_vpu[FMT_TYPE_BUTT] = {
+       SETUP_FMT_TBL(FMT_JPEGD , vpu_jpegd),
+       SETUP_FMT_TBL(FMT_H263D , vpu_defaultd),
+       SETUP_FMT_TBL(FMT_H264D , vpu_h264d),
+       EMPTY_FMT_TBL(FMT_H265D),
+
+       SETUP_FMT_TBL(FMT_MPEG1D, vpu_defaultd),
+       SETUP_FMT_TBL(FMT_MPEG2D, vpu_defaultd),
+       SETUP_FMT_TBL(FMT_MPEG4D, vpu_defaultd),
+
+       SETUP_FMT_TBL(FMT_VP6D  , vpu_vp6d),
+       SETUP_FMT_TBL(FMT_VP7D  , vpu_defaultd),
+       SETUP_FMT_TBL(FMT_VP8D  , vpu_vp8d),
+       EMPTY_FMT_TBL(FMT_VP9D),
+
+       SETUP_FMT_TBL(FMT_VC1D  , vpu_vc1d),
+       SETUP_FMT_TBL(FMT_AVSD  , vpu_defaultd),
+
+       SETUP_FMT_TBL(FMT_PP    , vpu_default_pp),
+
+       SETUP_FMT_TBL(FMT_JPEGE , vpu_defaulte),
+       SETUP_FMT_TBL(FMT_H264E , vpu_defaulte),
+       SETUP_FMT_TBL(FMT_VP8E  , vpu_vp8e),
+};
+
+#endif
diff --git a/drivers/video/rockchip/vcodec/vcodec_hw_vpu2.h b/drivers/video/rockchip/vcodec/vcodec_hw_vpu2.h
new file mode 100644 (file)
index 0000000..5da74b5
--- /dev/null
@@ -0,0 +1,275 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ *        Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H
+#define __ARCH_ARM_MACH_ROCKCHIP_VCODEC_HW_VPU2_H
+
+#include "vcodec_hw_info.h"
+
+/* hardware information */
+#define REG_NUM_VPU2_DEC               (159)
+#define REG_NUM_VPU2_DEC_START         (50)
+#define REG_NUM_VPU2_DEC_END           (159)
+#define REG_NUM_VPU2_PP                        (41)
+#define REG_NUM_VPU2_DEC_PP            (159)
+#define REG_NUM_VPU2_ENC               (184)
+#define REG_NUM_VPU2_DEC_OFFSET                (0x400)
+
+/* enable and gating register */
+#define VPU2_REG_EN_ENC                        103
+#define VPU2_REG_ENC_GATE              109
+#define VPU2_REG_ENC_GATE_BIT          BIT(4)
+
+#define VPU2_REG_EN_DEC                        57
+#define VPU2_REG_DEC_GATE              57
+#define VPU2_REG_DEC_GATE_BIT          BIT(4)
+#define VPU2_REG_EN_PP                 41
+#define VPU2_REG_PP_GATE               1
+#define VPU2_REG_PP_GATE_BIT           BIT(8)
+#define VPU2_REG_EN_DEC_PP             57
+#define VPU2_REG_DEC_PP_GATE           57
+#define VPU2_REG_DEC_PP_GATE_BIT       BIT(4)
+
+/* interrupt and error status register */
+#define VPU2_DEC_INTERRUPT_REGISTER    55
+#define VPU2_DEC_INTERRUPT_BIT         BIT(0)
+#define VPU2_DEC_READY_BIT             BIT(4)
+#define VPU2_DEC_BUS_ERROR_BIT         BIT(5)
+#define VPU2_DEC_BUFFER_EMPTY_BIT      BIT(6)
+#define VPU2_DEC_ASO_ERROR_BIT         BIT(8)
+#define VPU2_DEC_SLICE_DONE_BIT                BIT(9)
+#define VPU2_DEC_STREAM_ERROR_BIT      BIT(12)
+#define VPU2_DEC_TIMEOUT_BIT           BIT(13)
+#define VPU2_DEC_ERR_MASK              (VPU2_DEC_BUS_ERROR_BIT \
+                                       |VPU2_DEC_BUFFER_EMPTY_BIT \
+                                       |VPU2_DEC_STREAM_ERROR_BIT \
+                                       |VPU2_DEC_TIMEOUT_BIT)
+
+#define VPU2_PP_INTERRUPT_REGISTER     40
+#define VPU2_PP_INTERRUPT_BIT          BIT(0)
+#define VPU2_PP_READY_BIT              BIT(2)
+#define VPU2_PP_BUS_ERROR_BIT          BIT(3)
+#define VPU2_PP_ERR_MASK               VPU2_PP_BUS_ERROR_BIT
+#define VPU2_PP_PIPELINE_REGISTER      41
+#define VPU2_PP_PIPELINE_MODE_BIT      BIT(4)
+
+#define VPU2_ENC_INTERRUPT_REGISTER    109
+#define VPU2_ENC_INTERRUPT_BIT         BIT(0)
+#define VPU2_ENC_READY_BIT             BIT(1)
+#define VPU2_ENC_BUS_ERROR_BIT         BIT(4)
+#define VPU2_ENC_BUFFER_FULL_BIT       BIT(5)
+#define VPU2_ENC_TIMEOUT_BIT           BIT(6)
+#define VPU2_ENC_ERR_MASK              (VPU2_ENC_BUS_ERROR_BIT \
+                                       |VPU2_ENC_BUFFER_FULL_BIT \
+                                       |VPU2_ENC_TIMEOUT_BIT)
+
+static const enum FORMAT_TYPE vpu2_dec_fmt_tbl[] = {
+       [0]  = FMT_H264D,
+       [1]  = FMT_MPEG4D,
+       [2]  = FMT_H263D,
+       [3]  = FMT_JPEGD,
+       [4]  = FMT_VC1D,
+       [5]  = FMT_MPEG2D,
+       [6]  = FMT_MPEG1D,
+       [7]  = FMT_VP6D,
+       [8]  = FMT_TYPE_BUTT,
+       [9]  = FMT_VP7D,
+       [10] = FMT_VP8D,
+       [11] = FMT_AVSD,
+       [12] = FMT_TYPE_BUTT,
+       [13] = FMT_TYPE_BUTT,
+       [14] = FMT_TYPE_BUTT,
+       [15] = FMT_TYPE_BUTT,
+};
+
+static enum FORMAT_TYPE vpu2_dec_get_fmt(u32 *regs)
+{
+       u32 fmt_id = regs[53] & 0xf;
+       enum FORMAT_TYPE type = vpu2_dec_fmt_tbl[fmt_id];
+       return type;
+}
+
+static enum FORMAT_TYPE vpu2_pp_get_fmt(u32 *regs)
+{
+       return FMT_PP;
+}
+
+static const enum FORMAT_TYPE vpu2_enc_fmt_tbl[] = {
+       [0]  = FMT_TYPE_BUTT,
+       [1]  = FMT_VP8E,
+       [2]  = FMT_JPEGE,
+       [3]  = FMT_H264E,
+};
+
+static enum FORMAT_TYPE vpu2_enc_get_fmt(u32 *regs)
+{
+       u32 fmt_id = (regs[VPU2_REG_EN_ENC] >> 4) & 0x3;
+       enum FORMAT_TYPE type = vpu2_enc_fmt_tbl[fmt_id];
+       return type;
+}
+
+static struct vpu_task_info task_vpu2[TASK_TYPE_BUTT] = {
+       {
+               .name = "vpu2_enc",
+               .reg_en = VPU2_REG_EN_ENC,
+               .reg_gating = VPU2_REG_ENC_GATE,
+               .reg_irq = VPU2_ENC_INTERRUPT_REGISTER,
+               .reg_len = -1,
+               .reg_dir_mv = -1,
+               .reg_pps = -1,
+               .reg_pipe = -1,
+               .enable_mask = 0x30,
+               .gating_mask = VPU2_REG_ENC_GATE_BIT,
+               .pipe_mask = 0,
+               .irq_mask = VPU2_ENC_INTERRUPT_BIT,
+               .ready_mask = VPU2_ENC_READY_BIT,
+               .error_mask = VPU2_ENC_ERR_MASK,
+               .get_fmt = vpu2_enc_get_fmt,
+       },
+       {
+               .name = "vpu2_dec",
+               .reg_en = VPU2_REG_EN_DEC,
+               .reg_irq = VPU2_DEC_INTERRUPT_REGISTER,
+               .reg_len = 64,
+               .reg_dir_mv = 62,
+               .reg_pps = -1,
+               .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = VPU2_REG_DEC_GATE_BIT,
+               .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU2_DEC_INTERRUPT_BIT,
+               .ready_mask = VPU2_DEC_READY_BIT,
+               .error_mask = VPU2_DEC_ERR_MASK,
+               .get_fmt = vpu2_dec_get_fmt,
+       },
+       {
+               .name = "vpu2_pp",
+               .reg_en = VPU2_REG_EN_PP,
+               .reg_irq = VPU2_PP_INTERRUPT_REGISTER,
+               .reg_len = -1,
+               .reg_dir_mv = -1,
+               .reg_pps = -1,
+               .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = VPU2_REG_PP_GATE_BIT,
+               .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU2_PP_INTERRUPT_BIT,
+               .ready_mask = VPU2_PP_READY_BIT,
+               .error_mask = VPU2_PP_ERR_MASK,
+               .get_fmt = vpu2_pp_get_fmt,
+       },
+       {
+               .name = "vpu2_dec_pp",
+               .reg_en = VPU2_REG_EN_DEC_PP,
+               .reg_irq = VPU2_DEC_INTERRUPT_REGISTER,
+               .reg_len = 64,
+               .reg_dir_mv = 62,
+               .reg_pps = -1,
+               .reg_pipe = VPU2_PP_PIPELINE_REGISTER,
+               .enable_mask = 0,
+               .gating_mask = VPU2_REG_DEC_GATE_BIT,
+               .pipe_mask = VPU2_PP_PIPELINE_MODE_BIT,
+               .irq_mask = VPU2_DEC_INTERRUPT_BIT,
+               .ready_mask = VPU2_DEC_READY_BIT,
+               .error_mask = VPU2_DEC_ERR_MASK,
+               .get_fmt = vpu2_dec_get_fmt,
+       },
+};
+
+static struct vpu_hw_info hw_vpu2 = {
+       .hw_id          = VPU2_ID,
+
+       .enc_offset     = 0x0,
+       .enc_reg_num    = REG_NUM_VPU2_ENC,
+       .enc_io_size    = REG_NUM_VPU2_ENC * 4,
+
+       .dec_offset     = REG_NUM_VPU2_DEC_OFFSET,
+       .dec_reg_num    = REG_NUM_VPU2_DEC_PP,
+       .dec_io_size    = REG_NUM_VPU2_DEC_PP * 4,
+
+       .base_dec       = REG_NUM_VPU2_DEC_START,
+       .base_pp        = 0,
+       .base_dec_pp    = 0,
+       .end_dec        = REG_NUM_VPU2_DEC_END,
+       .end_pp         = REG_NUM_VPU2_PP,
+       .end_dec_pp     = REG_NUM_VPU2_DEC_END,
+};
+
+/*
+ * file handle translate information
+ */
+DEF_FMT_TRANS_TBL(vpu2_jpegd,
+                 131, 64, 63, 61, 21, 22
+);
+
+DEF_FMT_TRANS_TBL(vpu2_h264d,
+                 64, 63, 84, 85, 86, 87, 88, 89,
+                 90, 91, 92, 93, 94, 95, 96, 97,
+                 98, 99, 61, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vp6d,
+                 64, 63, 131, 136, 145, 61
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vp8d,
+                 149,  64,  63, 131, 136, 137, 140, 141,
+                 142, 143, 144, 145, 146, 147, 61
+);
+
+DEF_FMT_TRANS_TBL(vpu2_vc1d,
+                 64, 63, 131, 148, 134, 135, 145, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_dec,
+                 64, 63, 131, 148, 134, 135, 61, 62
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_pp,
+                 12, 13, 18, 19, 20, 21, 22
+);
+
+DEF_FMT_TRANS_TBL(vpu2_default_enc,
+                 77, 78, 56, 57, 63, 64, 48, 49,
+                 50, 81
+);
+
+const struct vpu_trans_info trans_vpu2[FMT_TYPE_BUTT] = {
+       SETUP_FMT_TBL(FMT_JPEGD , vpu2_jpegd),
+       SETUP_FMT_TBL(FMT_H263D , vpu2_default_dec),
+       SETUP_FMT_TBL(FMT_H264D , vpu2_h264d),
+       EMPTY_FMT_TBL(FMT_H265D),
+
+       SETUP_FMT_TBL(FMT_MPEG1D, vpu2_default_dec),
+       SETUP_FMT_TBL(FMT_MPEG2D, vpu2_default_dec),
+       SETUP_FMT_TBL(FMT_MPEG4D, vpu2_default_dec),
+
+       SETUP_FMT_TBL(FMT_VP6D  , vpu2_vp6d),
+       SETUP_FMT_TBL(FMT_VP7D  , vpu2_default_dec),
+       SETUP_FMT_TBL(FMT_VP8D  , vpu2_vp8d),
+       EMPTY_FMT_TBL(FMT_VP9D),
+
+       SETUP_FMT_TBL(FMT_PP    , vpu2_default_pp),
+
+       SETUP_FMT_TBL(FMT_VC1D  , vpu2_vc1d),
+       SETUP_FMT_TBL(FMT_AVSD  , vpu2_default_dec),
+
+       SETUP_FMT_TBL(FMT_JPEGE , vpu2_default_enc),
+       SETUP_FMT_TBL(FMT_H264E , vpu2_default_enc),
+       SETUP_FMT_TBL(FMT_VP8E  , vpu2_default_enc),
+};
+
+#endif
diff --git a/drivers/video/rockchip/vcodec/vcodec_service.c b/drivers/video/rockchip/vcodec/vcodec_service.c
new file mode 100644 (file)
index 0000000..d97b0f5
--- /dev/null
@@ -0,0 +1,2938 @@
+/**
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ *        Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <linux/cdev.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include <linux/rockchip/cpu.h>
+#include <linux/rockchip/cru.h>
+#include <linux/rockchip/pmu.h>
+#include <linux/rockchip/grf.h>
+
+#if defined(CONFIG_ION_ROCKCHIP)
+#include <linux/rockchip_ion.h>
+#endif
+
+#if defined(CONFIG_RK_IOMMU) & defined(CONFIG_ION_ROCKCHIP)
+#define CONFIG_VCODEC_MMU
+#include <linux/rockchip-iovmm.h>
+#include <linux/dma-buf.h>
+#endif
+
+#include "vcodec_hw_info.h"
+#include "vcodec_hw_vpu.h"
+#include "vcodec_hw_rkv.h"
+#include "vcodec_hw_vpu2.h"
+
+#include "vcodec_service.h"
+
+/*
+ * debug flag usage:
+ * +------+-------------------+
+ * | 8bit |      24bit        |
+ * +------+-------------------+
+ *  0~23 bit is for different information type
+ * 24~31 bit is for information print format
+ */
+
+#define DEBUG_POWER                            0x00000001
+#define DEBUG_CLOCK                            0x00000002
+#define DEBUG_IRQ_STATUS                       0x00000004
+#define DEBUG_IOMMU                            0x00000008
+#define DEBUG_IOCTL                            0x00000010
+#define DEBUG_FUNCTION                         0x00000020
+#define DEBUG_REGISTER                         0x00000040
+#define DEBUG_EXTRA_INFO                       0x00000080
+#define DEBUG_TIMING                           0x00000100
+#define DEBUG_TASK_INFO                                0x00000200
+
+#define DEBUG_SET_REG                          0x00001000
+#define DEBUG_GET_REG                          0x00002000
+#define DEBUG_PPS_FILL                         0x00004000
+#define DEBUG_IRQ_CHECK                                0x00008000
+#define DEBUG_CACHE_32B                                0x00010000
+
+#define PRINT_FUNCTION                         0x80000000
+#define PRINT_LINE                             0x40000000
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "bit switch for vcodec_service debug information");
+
+#define VCODEC_CLOCK_ENABLE    1
+
+/*
+ * hardware information organization
+ *
+ * In order to support multiple hardware with different version the hardware
+ * information is organized as follow:
+ *
+ * 1. First, index hardware by register size / position.
+ *    These information is fix for each hardware and do not relate to runtime
+ *    work flow. It only related to resource allocation.
+ *    Descriptor: struct vpu_hw_info
+ *
+ * 2. Then, index hardware by runtime configuration
+ *    These information is related to runtime setting behave including enable
+ *    register, irq register and other key control flag
+ *    Descriptor: struct vpu_task_info
+ *
+ * 3. Final, on iommu case the fd translation is required
+ *    Descriptor: struct vpu_trans_info
+ */
+
+enum VPU_FREQ {
+       VPU_FREQ_200M,
+       VPU_FREQ_266M,
+       VPU_FREQ_300M,
+       VPU_FREQ_400M,
+       VPU_FREQ_500M,
+       VPU_FREQ_600M,
+       VPU_FREQ_DEFAULT,
+       VPU_FREQ_BUT,
+};
+
+struct extra_info_elem {
+       u32 index;
+       u32 offset;
+};
+
+#define EXTRA_INFO_MAGIC       0x4C4A46
+
+struct extra_info_for_iommu {
+       u32 magic;
+       u32 cnt;
+       struct extra_info_elem elem[20];
+};
+
+#define MHZ                                    (1000*1000)
+#define SIZE_REG(reg)                          ((reg)*4)
+
+static struct vcodec_info vcodec_info_set[] = {
+       [0] = {
+               .hw_id          = VPU_ID_8270,
+               .hw_info        = &hw_vpu_8270,
+               .task_info      = task_vpu,
+               .trans_info     = trans_vpu,
+       },
+       [1] = {
+               .hw_id          = VPU_ID_4831,
+               .hw_info        = &hw_vpu_4831,
+               .task_info      = task_vpu,
+               .trans_info     = trans_vpu,
+       },
+       [2] = {
+               .hw_id          = VPU_DEC_ID_9190,
+               .hw_info        = &hw_vpu_9190,
+               .task_info      = task_vpu,
+               .trans_info     = trans_vpu,
+       },
+       [3] = {
+               .hw_id          = HEVC_ID,
+               .hw_info        = &hw_rkhevc,
+               .task_info      = task_rkv,
+               .trans_info     = trans_rkv,
+       },
+       [4] = {
+               .hw_id          = RKV_DEC_ID,
+               .hw_info        = &hw_rkvdec,
+               .task_info      = task_rkv,
+               .trans_info     = trans_rkv,
+       },
+       [5] = {
+               .hw_id          = VPU2_ID,
+               .hw_info        = &hw_vpu2,
+               .task_info      = task_vpu2,
+               .trans_info     = trans_vpu2,
+       },
+};
+
+#define DEBUG
+#ifdef DEBUG
+#define vpu_debug_func(type, fmt, args...)                     \
+       do {                                                    \
+               if (unlikely(debug & type)) {                   \
+                       pr_info("%s:%d: " fmt,                  \
+                                __func__, __LINE__, ##args);   \
+               }                                               \
+       } while (0)
+#define vpu_debug(type, fmt, args...)                          \
+       do {                                                    \
+               if (unlikely(debug & type)) {                   \
+                       pr_info(fmt, ##args);                   \
+               }                                               \
+       } while (0)
+#else
+#define vpu_debug_func(level, fmt, args...)
+#define vpu_debug(level, fmt, args...)
+#endif
+
+#define vpu_debug_enter() vpu_debug_func(DEBUG_FUNCTION, "enter\n")
+#define vpu_debug_leave() vpu_debug_func(DEBUG_FUNCTION, "leave\n")
+
+#define vpu_err(fmt, args...)                          \
+               pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
+
+enum VPU_DEC_FMT {
+       VPU_DEC_FMT_H264,
+       VPU_DEC_FMT_MPEG4,
+       VPU_DEC_FMT_H263,
+       VPU_DEC_FMT_JPEG,
+       VPU_DEC_FMT_VC1,
+       VPU_DEC_FMT_MPEG2,
+       VPU_DEC_FMT_MPEG1,
+       VPU_DEC_FMT_VP6,
+       VPU_DEC_FMT_RESERV0,
+       VPU_DEC_FMT_VP7,
+       VPU_DEC_FMT_VP8,
+       VPU_DEC_FMT_AVS,
+       VPU_DEC_FMT_RES
+};
+
+/**
+ * struct for process session which connect to vpu
+ *
+ * @author ChenHengming (2011-5-3)
+ */
+struct vpu_session {
+       enum VPU_CLIENT_TYPE type;
+       /* a linked list of data so we can access them for debugging */
+       struct list_head list_session;
+       /* a linked list of register data waiting for process */
+       struct list_head waiting;
+       /* a linked list of register data in processing */
+       struct list_head running;
+       /* a linked list of register data processed */
+       struct list_head done;
+       wait_queue_head_t wait;
+       pid_t pid;
+       atomic_t task_running;
+};
+
+/**
+ * struct for process register set
+ *
+ * @author ChenHengming (2011-5-4)
+ */
+struct vpu_reg {
+       enum VPU_CLIENT_TYPE type;
+       enum VPU_FREQ freq;
+       struct vpu_session *session;
+       struct vpu_subdev_data *data;
+       struct vpu_task_info *task;
+       const struct vpu_trans_info *trans;
+
+       /* link to vpu service session */
+       struct list_head session_link;
+       /* link to register set list */
+       struct list_head status_link;
+
+       unsigned long size;
+       struct list_head mem_region_list;
+       u32 dec_base;
+       u32 *reg;
+};
+
+struct vpu_device {
+       atomic_t irq_count_codec;
+       atomic_t irq_count_pp;
+       unsigned int iosize;
+       u32 *regs;
+};
+
+enum vcodec_device_id {
+       VCODEC_DEVICE_ID_VPU,
+       VCODEC_DEVICE_ID_HEVC,
+       VCODEC_DEVICE_ID_COMBO,
+       VCODEC_DEVICE_ID_RKVDEC,
+       VCODEC_DEVICE_ID_BUTT
+};
+
+enum VCODEC_RUNNING_MODE {
+       VCODEC_RUNNING_MODE_NONE = -1,
+       VCODEC_RUNNING_MODE_VPU,
+       VCODEC_RUNNING_MODE_HEVC,
+       VCODEC_RUNNING_MODE_RKVDEC
+};
+
+struct vcodec_mem_region {
+       struct list_head srv_lnk;
+       struct list_head reg_lnk;
+       struct list_head session_lnk;
+       unsigned long iova;     /* virtual address for iommu */
+       unsigned long len;
+       u32 reg_idx;
+       struct ion_handle *hdl;
+};
+
+enum vpu_ctx_state {
+       MMU_ACTIVATED   = BIT(0)
+};
+
+struct vpu_subdev_data {
+       struct cdev cdev;
+       dev_t dev_t;
+       struct class *cls;
+       struct device *child_dev;
+
+       int irq_enc;
+       int irq_dec;
+       struct vpu_service_info *pservice;
+
+       u32 *regs;
+       enum VCODEC_RUNNING_MODE mode;
+       struct list_head lnk_service;
+
+       struct device *dev;
+
+       struct vpu_device enc_dev;
+       struct vpu_device dec_dev;
+
+       enum VPU_HW_ID hw_id;
+       struct vpu_hw_info *hw_info;
+       struct vpu_task_info *task_info;
+       const struct vpu_trans_info *trans_info;
+
+       u32 reg_size;
+       unsigned long state;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_dir;
+       struct dentry *debugfs_file_regs;
+#endif
+
+       struct device *mmu_dev;
+};
+
+struct vpu_service_info {
+       struct wake_lock wake_lock;
+       struct delayed_work power_off_work;
+       /* vpu service structure global lock */
+       struct mutex lock;
+       /* link to link_reg in struct vpu_reg */
+       struct list_head waiting;
+       /* link to link_reg in struct vpu_reg */
+       struct list_head running;
+       /* link to link_reg in struct vpu_reg */
+       struct list_head done;
+       /* link to list_session in struct vpu_session */
+       struct list_head session;
+       atomic_t total_running;
+       atomic_t enabled;
+       atomic_t power_on_cnt;
+       atomic_t power_off_cnt;
+       struct vpu_reg *reg_codec;
+       struct vpu_reg *reg_pproc;
+       struct vpu_reg *reg_resev;
+       struct vpu_dec_config dec_config;
+       struct vpu_enc_config enc_config;
+
+       bool auto_freq;
+       bool bug_dec_addr;
+       atomic_t freq_status;
+
+       struct clk *aclk_vcodec;
+       struct clk *hclk_vcodec;
+       struct clk *clk_core;
+       struct clk *clk_cabac;
+       struct clk *pd_video;
+
+#ifdef CONFIG_RESET_CONTROLLER
+       struct reset_control *rst_a;
+       struct reset_control *rst_h;
+       struct reset_control *rst_v;
+#endif
+       struct device *dev;
+
+       u32 irq_status;
+       atomic_t reset_request;
+       struct ion_client *ion_client;
+       struct list_head mem_region_list;
+
+       enum vcodec_device_id dev_id;
+
+       enum VCODEC_RUNNING_MODE curr_mode;
+       u32 prev_mode;
+
+       struct delayed_work simulate_work;
+
+       u32 mode_bit;
+       u32 mode_ctrl;
+       u32 *reg_base;
+       u32 ioaddr;
+       struct regmap *grf;
+       u32 *grf_base;
+
+       char *name;
+
+       u32 subcnt;
+       struct list_head subdev_list;
+};
+
+struct vpu_request {
+       u32 *req;
+       u32 size;
+};
+
+#ifdef CONFIG_COMPAT
+struct compat_vpu_request {
+       compat_uptr_t req;
+       u32 size;
+};
+#endif
+
+/* debugfs root directory for all device (vpu, hevc).*/
+static struct dentry *parent;
+
+#ifdef CONFIG_DEBUG_FS
+static int vcodec_debugfs_init(void);
+static void vcodec_debugfs_exit(void);
+static struct dentry *vcodec_debugfs_create_device_dir(
+               char *dirname, struct dentry *parent);
+static int debug_vcodec_open(struct inode *inode, struct file *file);
+
+static const struct file_operations debug_vcodec_fops = {
+       .open = debug_vcodec_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+#endif
+
+#define VDPU_SOFT_RESET_REG    101
+#define VDPU_CLEAN_CACHE_REG   516
+#define VEPU_CLEAN_CACHE_REG   772
+#define HEVC_CLEAN_CACHE_REG   260
+
+#define VPU_REG_ENABLE(base, reg)      writel_relaxed(1, base + reg)
+
+#define VDPU_SOFT_RESET(base)  VPU_REG_ENABLE(base, VDPU_SOFT_RESET_REG)
+#define VDPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VDPU_CLEAN_CACHE_REG)
+#define VEPU_CLEAN_CACHE(base) VPU_REG_ENABLE(base, VEPU_CLEAN_CACHE_REG)
+#define HEVC_CLEAN_CACHE(base) VPU_REG_ENABLE(base, HEVC_CLEAN_CACHE_REG)
+
+#define VPU_POWER_OFF_DELAY            (4 * HZ) /* 4s */
+#define VPU_TIMEOUT_DELAY              (2 * HZ) /* 2s */
+
+static void time_record(struct vpu_task_info *task, int is_end)
+{
+       if (unlikely(debug & DEBUG_TIMING) && task)
+               do_gettimeofday((is_end) ? (&task->end) : (&task->start));
+}
+
+static void time_diff(struct vpu_task_info *task)
+{
+       vpu_debug(DEBUG_TIMING, "%s task: %ld ms\n", task->name,
+                 (task->end.tv_sec  - task->start.tv_sec)  * 1000 +
+                 (task->end.tv_usec - task->start.tv_usec) / 1000);
+}
+
+static void vcodec_enter_mode(struct vpu_subdev_data *data)
+{
+       int bits;
+       u32 raw = 0;
+       struct vpu_service_info *pservice = data->pservice;
+#if defined(CONFIG_VCODEC_MMU)
+       struct vpu_subdev_data *subdata, *n;
+#endif
+       if (pservice->subcnt < 2) {
+#if defined(CONFIG_VCODEC_MMU)
+               if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
+                       set_bit(MMU_ACTIVATED, &data->state);
+                       if (atomic_read(&pservice->enabled))
+                               rockchip_iovmm_activate(data->dev);
+                       else
+                               BUG_ON(!atomic_read(&pservice->enabled));
+               }
+#endif
+               return;
+       }
+
+       if (pservice->curr_mode == data->mode)
+               return;
+
+       vpu_debug(DEBUG_IOMMU, "vcodec enter mode %d\n", data->mode);
+#if defined(CONFIG_VCODEC_MMU)
+       list_for_each_entry_safe(subdata, n,
+                                &pservice->subdev_list, lnk_service) {
+               if (data != subdata && subdata->mmu_dev &&
+                   test_bit(MMU_ACTIVATED, &subdata->state)) {
+                       clear_bit(MMU_ACTIVATED, &subdata->state);
+                       rockchip_iovmm_deactivate(subdata->dev);
+               }
+       }
+#endif
+       bits = 1 << pservice->mode_bit;
+#ifdef CONFIG_MFD_SYSCON
+       if (pservice->grf) {
+               regmap_read(pservice->grf, pservice->mode_ctrl, &raw);
+
+               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+                       regmap_write(pservice->grf, pservice->mode_ctrl,
+                                    raw | bits | (bits << 16));
+               else
+                       regmap_write(pservice->grf, pservice->mode_ctrl,
+                                    (raw & (~bits)) | (bits << 16));
+       } else if (pservice->grf_base) {
+               u32 *grf_base = pservice->grf_base;
+
+               raw = readl_relaxed(grf_base + pservice->mode_ctrl / 4);
+               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+                       writel_relaxed(raw | bits | (bits << 16),
+                                      grf_base + pservice->mode_ctrl / 4);
+               else
+                       writel_relaxed((raw & (~bits)) | (bits << 16),
+                                      grf_base + pservice->mode_ctrl / 4);
+       } else {
+               vpu_err("no grf resource define, switch decoder failed\n");
+               return;
+       }
+#else
+       if (pservice->grf_base) {
+               u32 *grf_base = pservice->grf_base;
+
+               raw = readl_relaxed(grf_base + pservice->mode_ctrl / 4);
+               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+                       writel_relaxed(raw | bits | (bits << 16),
+                                      grf_base + pservice->mode_ctrl / 4);
+               else
+                       writel_relaxed((raw & (~bits)) | (bits << 16),
+                                      grf_base + pservice->mode_ctrl / 4);
+       } else {
+               vpu_err("no grf resource define, switch decoder failed\n");
+               return;
+       }
+#endif
+#if defined(CONFIG_VCODEC_MMU)
+       if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
+               set_bit(MMU_ACTIVATED, &data->state);
+               if (atomic_read(&pservice->enabled))
+                       rockchip_iovmm_activate(data->dev);
+               else
+                       BUG_ON(!atomic_read(&pservice->enabled));
+       }
+#endif
+       pservice->prev_mode = pservice->curr_mode;
+       pservice->curr_mode = data->mode;
+}
+
+static void vcodec_exit_mode(struct vpu_subdev_data *data)
+{
+       if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
+               clear_bit(MMU_ACTIVATED, &data->state);
+#if defined(CONFIG_VCODEC_MMU)
+               rockchip_iovmm_deactivate(data->dev);
+#endif
+               data->pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
+       }
+}
+
+static int vpu_get_clk(struct vpu_service_info *pservice)
+{
+#if VCODEC_CLOCK_ENABLE
+       struct device *dev = pservice->dev;
+
+       switch (pservice->dev_id) {
+       case VCODEC_DEVICE_ID_HEVC:
+               pservice->pd_video = devm_clk_get(dev, "pd_hevc");
+               if (IS_ERR(pservice->pd_video)) {
+                       dev_err(dev, "failed on clk_get pd_hevc\n");
+                       return -1;
+               }
+       case VCODEC_DEVICE_ID_COMBO:
+       case VCODEC_DEVICE_ID_RKVDEC:
+               pservice->clk_cabac = devm_clk_get(dev, "clk_cabac");
+               if (IS_ERR(pservice->clk_cabac)) {
+                       dev_err(dev, "failed on clk_get clk_cabac\n");
+                       pservice->clk_cabac = NULL;
+               }
+               pservice->clk_core = devm_clk_get(dev, "clk_core");
+               if (IS_ERR(pservice->clk_core)) {
+                       dev_err(dev, "failed on clk_get clk_core\n");
+                       return -1;
+               }
+       case VCODEC_DEVICE_ID_VPU:
+               pservice->aclk_vcodec = devm_clk_get(dev, "aclk_vcodec");
+               if (IS_ERR(pservice->aclk_vcodec)) {
+                       dev_err(dev, "failed on clk_get aclk_vcodec\n");
+                       return -1;
+               }
+
+               pservice->hclk_vcodec = devm_clk_get(dev, "hclk_vcodec");
+               if (IS_ERR(pservice->hclk_vcodec)) {
+                       dev_err(dev, "failed on clk_get hclk_vcodec\n");
+                       return -1;
+               }
+               if (pservice->pd_video == NULL) {
+                       pservice->pd_video = devm_clk_get(dev, "pd_video");
+                       if (IS_ERR(pservice->pd_video)) {
+                               pservice->pd_video = NULL;
+                               dev_info(dev, "do not have pd_video\n");
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+#else
+       return 0;
+#endif
+}
+
+static void vpu_put_clk(struct vpu_service_info *pservice)
+{
+#if VCODEC_CLOCK_ENABLE
+       if (pservice->pd_video)
+               devm_clk_put(pservice->dev, pservice->pd_video);
+       if (pservice->aclk_vcodec)
+               devm_clk_put(pservice->dev, pservice->aclk_vcodec);
+       if (pservice->hclk_vcodec)
+               devm_clk_put(pservice->dev, pservice->hclk_vcodec);
+       if (pservice->clk_core)
+               devm_clk_put(pservice->dev, pservice->clk_core);
+       if (pservice->clk_cabac)
+               devm_clk_put(pservice->dev, pservice->clk_cabac);
+#endif
+}
+
+static void vpu_reset(struct vpu_subdev_data *data)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       enum pmu_idle_req type = IDLE_REQ_VIDEO;
+
+       if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC)
+               type = IDLE_REQ_HEVC;
+
+       pr_info("%s: resetting...", dev_name(pservice->dev));
+
+#if defined(CONFIG_ARCH_RK29)
+       clk_disable(aclk_ddr_vepu);
+       cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
+       cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);
+       mdelay(10);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);
+       cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);
+       cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);
+       clk_enable(aclk_ddr_vepu);
+#elif defined(CONFIG_ARCH_RK30)
+       pmu_set_idle_request(IDLE_REQ_VIDEO, true);
+       cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true);
+       cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, true);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AXI, true);
+       mdelay(1);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AXI, false);
+       cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false);
+       cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, false);
+       cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);
+       pmu_set_idle_request(IDLE_REQ_VIDEO, false);
+#else
+#endif
+       WARN_ON(pservice->reg_codec != NULL);
+       WARN_ON(pservice->reg_pproc != NULL);
+       WARN_ON(pservice->reg_resev != NULL);
+       pservice->reg_codec = NULL;
+       pservice->reg_pproc = NULL;
+       pservice->reg_resev = NULL;
+
+       pr_info("for 3288/3368...");
+#if 0 //def CONFIG_RESET_CONTROLLER
+       if (pservice->rst_a && pservice->rst_h) {
+               if (rockchip_pmu_ops.set_idle_request)
+                       rockchip_pmu_ops.set_idle_request(type, true);
+               pr_info("reset in\n");
+               if (pservice->rst_v)
+                       reset_control_assert(pservice->rst_v);
+               reset_control_assert(pservice->rst_a);
+               reset_control_assert(pservice->rst_h);
+               udelay(5);
+               reset_control_deassert(pservice->rst_h);
+               reset_control_deassert(pservice->rst_a);
+               if (pservice->rst_v)
+                       reset_control_deassert(pservice->rst_v);
+               if (rockchip_pmu_ops.set_idle_request)
+                       rockchip_pmu_ops.set_idle_request(type, false);
+       }
+#endif
+
+#if defined(CONFIG_VCODEC_MMU)
+       if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
+               clear_bit(MMU_ACTIVATED, &data->state);
+               if (atomic_read(&pservice->enabled))
+                       rockchip_iovmm_deactivate(data->dev);
+               else
+                       BUG_ON(!atomic_read(&pservice->enabled));
+       }
+#endif
+       atomic_set(&pservice->reset_request, 0);
+       pr_info("done\n");
+}
+
+static void reg_deinit(struct vpu_subdev_data *data, struct vpu_reg *reg);
+static void vpu_service_session_clear(struct vpu_subdev_data *data,
+                                     struct vpu_session *session)
+{
+       struct vpu_reg *reg, *n;
+
+       list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
+               reg_deinit(data, reg);
+       }
+       list_for_each_entry_safe(reg, n, &session->running, session_link) {
+               reg_deinit(data, reg);
+       }
+       list_for_each_entry_safe(reg, n, &session->done, session_link) {
+               reg_deinit(data, reg);
+       }
+}
+
+static void vpu_service_dump(struct vpu_service_info *pservice)
+{
+}
+
+
+static void vpu_service_power_off(struct vpu_service_info *pservice)
+{
+       int total_running;
+       struct vpu_subdev_data *data = NULL, *n;
+       int ret = atomic_add_unless(&pservice->enabled, -1, 0);
+
+       if (!ret)
+               return;
+
+       total_running = atomic_read(&pservice->total_running);
+       if (total_running) {
+               pr_alert("alert: power off when %d task running!!\n",
+                        total_running);
+               mdelay(50);
+               pr_alert("alert: delay 50 ms for running task\n");
+               vpu_service_dump(pservice);
+       }
+
+       pr_info("%s: power off...", dev_name(pservice->dev));
+
+       udelay(5);
+
+#if defined(CONFIG_VCODEC_MMU)
+       list_for_each_entry_safe(data, n, &pservice->subdev_list, lnk_service) {
+               if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
+                       clear_bit(MMU_ACTIVATED, &data->state);
+                       rockchip_iovmm_deactivate(data->dev);
+               }
+       }
+       pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
+#endif
+
+#if VCODEC_CLOCK_ENABLE
+               if (pservice->pd_video)
+                       clk_disable_unprepare(pservice->pd_video);
+               if (pservice->hclk_vcodec)
+                       clk_disable_unprepare(pservice->hclk_vcodec);
+               if (pservice->aclk_vcodec)
+                       clk_disable_unprepare(pservice->aclk_vcodec);
+               if (pservice->clk_core)
+                       clk_disable_unprepare(pservice->clk_core);
+               if (pservice->clk_cabac)
+                       clk_disable_unprepare(pservice->clk_cabac);
+#endif
+
+       atomic_add(1, &pservice->power_off_cnt);
+       wake_unlock(&pservice->wake_lock);
+       pr_info("done\n");
+}
+
+static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice)
+{
+       queue_delayed_work(system_wq, &pservice->power_off_work,
+                          VPU_POWER_OFF_DELAY);
+}
+
+static void vpu_power_off_work(struct work_struct *work_s)
+{
+       struct delayed_work *dlwork = container_of(work_s,
+                       struct delayed_work, work);
+       struct vpu_service_info *pservice = container_of(dlwork,
+                       struct vpu_service_info, power_off_work);
+
+       if (mutex_trylock(&pservice->lock)) {
+               vpu_service_power_off(pservice);
+               mutex_unlock(&pservice->lock);
+       } else {
+               /* Come back later if the device is busy... */
+               vpu_queue_power_off_work(pservice);
+       }
+}
+
+static void vpu_service_power_on(struct vpu_service_info *pservice)
+{
+       int ret;
+       static ktime_t last;
+       ktime_t now = ktime_get();
+
+       if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {
+               cancel_delayed_work_sync(&pservice->power_off_work);
+               vpu_queue_power_off_work(pservice);
+               last = now;
+       }
+       ret = atomic_add_unless(&pservice->enabled, 1, 1);
+       if (!ret)
+               return;
+
+       pr_info("%s: power on\n", dev_name(pservice->dev));
+
+#define BIT_VCODEC_CLK_SEL     (1<<10)
+       if (cpu_is_rk312x())
+               writel_relaxed(readl_relaxed(RK_GRF_VIRT + RK312X_GRF_SOC_CON1)
+                       | BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16),
+                       RK_GRF_VIRT + RK312X_GRF_SOC_CON1);
+
+#if VCODEC_CLOCK_ENABLE
+       if (pservice->aclk_vcodec)
+               clk_prepare_enable(pservice->aclk_vcodec);
+       if (pservice->hclk_vcodec)
+               clk_prepare_enable(pservice->hclk_vcodec);
+       if (pservice->clk_core)
+               clk_prepare_enable(pservice->clk_core);
+       if (pservice->clk_cabac)
+               clk_prepare_enable(pservice->clk_cabac);
+       if (pservice->pd_video)
+               clk_prepare_enable(pservice->pd_video);
+#endif
+
+       udelay(5);
+       atomic_add(1, &pservice->power_on_cnt);
+       wake_lock(&pservice->wake_lock);
+}
+
+static inline bool reg_check_interlace(struct vpu_reg *reg)
+{
+       u32 type = (reg->reg[3] & (1 << 23));
+
+       return (type > 0);
+}
+
+static inline enum VPU_DEC_FMT reg_check_fmt(struct vpu_reg *reg)
+{
+       enum VPU_DEC_FMT type = (enum VPU_DEC_FMT)((reg->reg[3] >> 28) & 0xf);
+
+       return type;
+}
+
+static inline int reg_probe_width(struct vpu_reg *reg)
+{
+       int width_in_mb = reg->reg[4] >> 23;
+
+       return width_in_mb * 16;
+}
+
+static inline int reg_probe_hevc_y_stride(struct vpu_reg *reg)
+{
+       int y_virstride = reg->reg[8];
+
+       return y_virstride;
+}
+
+static int vcodec_fd_to_iova(struct vpu_subdev_data *data,
+                            struct vpu_reg *reg, int fd)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct ion_handle *hdl;
+       int ret = 0;
+       struct vcodec_mem_region *mem_region;
+
+       hdl = ion_import_dma_buf(pservice->ion_client, fd);
+       if (IS_ERR(hdl)) {
+               vpu_err("import dma-buf from fd %d failed\n", fd);
+               return PTR_ERR(hdl);
+       }
+       mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
+
+       if (mem_region == NULL) {
+               vpu_err("allocate memory for iommu memory region failed\n");
+               ion_free(pservice->ion_client, hdl);
+               return -1;
+       }
+
+       mem_region->hdl = hdl;
+       if (data->mmu_dev)
+               ret = ion_map_iommu(data->dev, pservice->ion_client,
+                                   mem_region->hdl, &mem_region->iova,
+                                   &mem_region->len);
+       else
+               ret = ion_phys(pservice->ion_client,
+                              mem_region->hdl,
+                              (ion_phys_addr_t *)&mem_region->iova,
+                              (size_t *)&mem_region->len);
+
+       if (ret < 0) {
+               vpu_err("fd %d ion map iommu failed\n", fd);
+               kfree(mem_region);
+               ion_free(pservice->ion_client, hdl);
+               return ret;
+       }
+       INIT_LIST_HEAD(&mem_region->reg_lnk);
+       list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);
+       return mem_region->iova;
+}
+
+/*
+ * NOTE: rkvdec/rkhevc put scaling list address in pps buffer hardware will read
+ * it by pps id in video stream data.
+ *
+ * So we need to translate the address in iommu case. The address data is also
+ * 10bit fd + 22bit offset mode.
+ * Because userspace decoder do not give the pps id in the register file sets
+ * kernel driver need to translate each scaling list address in pps buffer which
+ * means 256 pps for H.264, 64 pps for H.265.
+ *
+ * In order to optimize the performance kernel driver ask userspace decoder to
+ * set all scaling list address in pps buffer to the same one which will be used
+ * on current decoding task. Then kernel driver can only translate the first
+ * address then copy it all pps buffer.
+ */
+static void fill_scaling_list_addr_in_pps(
+               struct vpu_subdev_data *data,
+               struct vpu_reg *reg,
+               char *pps,
+               int pps_info_count,
+               int pps_info_size,
+               int scaling_list_addr_offset)
+{
+       int base = scaling_list_addr_offset;
+       int scaling_fd = 0;
+       u32 scaling_offset;
+
+       scaling_offset  = (u32)pps[base + 0];
+       scaling_offset += (u32)pps[base + 1] << 8;
+       scaling_offset += (u32)pps[base + 2] << 16;
+       scaling_offset += (u32)pps[base + 3] << 24;
+
+       scaling_fd = scaling_offset & 0x3ff;
+       scaling_offset = scaling_offset >> 10;
+
+       if (scaling_fd > 0) {
+               int i = 0;
+               u32 tmp = vcodec_fd_to_iova(data, reg, scaling_fd);
+               tmp += scaling_offset;
+
+               for (i = 0; i < pps_info_count; i++, base += pps_info_size) {
+                       pps[base + 0] = (tmp >>  0) & 0xff;
+                       pps[base + 1] = (tmp >>  8) & 0xff;
+                       pps[base + 2] = (tmp >> 16) & 0xff;
+                       pps[base + 3] = (tmp >> 24) & 0xff;
+               }
+       }
+}
+
+static int vcodec_bufid_to_iova(struct vpu_subdev_data *data, const u8 *tbl,
+                               int size, struct vpu_reg *reg,
+                               struct extra_info_for_iommu *ext_inf)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_task_info *task = reg->task;
+       enum FORMAT_TYPE type;
+       struct ion_handle *hdl;
+       int ret = 0;
+       struct vcodec_mem_region *mem_region;
+       int i;
+       int offset = 0;
+
+       if (tbl == NULL || size <= 0) {
+               dev_err(pservice->dev, "input arguments invalidate\n");
+               return -1;
+       }
+
+       if (task->get_fmt)
+               type = task->get_fmt(reg->reg);
+       else {
+               pr_err("invalid task with NULL get_fmt\n");
+               return -1;
+       }
+
+       for (i = 0; i < size; i++) {
+               int usr_fd = reg->reg[tbl[i]] & 0x3FF;
+
+               /* if userspace do not set the fd at this register, skip */
+               if (usr_fd == 0)
+                       continue;
+
+               /*
+                * special offset scale case
+                *
+                * This translation is for fd + offset translation.
+                * One register has 32bits. We need to transfer both buffer file
+                * handle and the start address offset so we packet file handle
+                * and offset together using below format.
+                *
+                *  0~9  bit for buffer file handle range 0 ~ 1023
+                * 10~31 bit for offset range 0 ~ 4M
+                *
+                * But on 4K case the offset can be larger the 4M
+                * So on H.264 4K vpu/vpu2 decoder we scale the offset by 16
+                * But MPEG4 will use the same register for colmv and it do not
+                * need scale.
+                *
+                * RKVdec do not have this issue.
+                */
+               if ((type == FMT_H264D || type == FMT_VP9D) &&
+                   task->reg_dir_mv > 0 && task->reg_dir_mv == tbl[i])
+                       offset = reg->reg[tbl[i]] >> 10 << 4;
+               else
+                       offset = reg->reg[tbl[i]] >> 10;
+
+               vpu_debug(DEBUG_IOMMU, "pos %3d fd %3d offset %10d\n",
+                         tbl[i], usr_fd, offset);
+
+               hdl = ion_import_dma_buf(pservice->ion_client, usr_fd);
+               if (IS_ERR(hdl)) {
+                       dev_err(pservice->dev,
+                               "import dma-buf from fd %d failed, reg[%d]\n",
+                               usr_fd, tbl[i]);
+                       return PTR_ERR(hdl);
+               }
+
+               if (task->reg_pps > 0 && task->reg_pps == tbl[i]) {
+                       int pps_info_offset;
+                       int pps_info_count;
+                       int pps_info_size;
+                       int scaling_list_addr_offset;
+
+                       switch (type) {
+                       case FMT_H264D: {
+                               pps_info_offset = offset;
+                               pps_info_count = 256;
+                               pps_info_size = 32;
+                               scaling_list_addr_offset = 23;
+                       } break;
+                       case FMT_H265D: {
+                               pps_info_offset = 0;
+                               pps_info_count = 64;
+                               pps_info_size = 80;
+                               scaling_list_addr_offset = 74;
+                       } break;
+                       default: {
+                               pps_info_offset = 0;
+                               pps_info_count = 0;
+                               pps_info_size = 0;
+                               scaling_list_addr_offset = 0;
+                       } break;
+                       }
+
+                       vpu_debug(DEBUG_PPS_FILL,
+                                 "scaling list filling parameter:\n");
+                       vpu_debug(DEBUG_PPS_FILL,
+                                 "pps_info_offset %d\n", pps_info_offset);
+                       vpu_debug(DEBUG_PPS_FILL,
+                                 "pps_info_count  %d\n", pps_info_count);
+                       vpu_debug(DEBUG_PPS_FILL,
+                                 "pps_info_size   %d\n", pps_info_size);
+                       vpu_debug(DEBUG_PPS_FILL,
+                                 "scaling_list_addr_offset %d\n",
+                                 scaling_list_addr_offset);
+
+                       if (pps_info_count) {
+                               char *pps = (char *)ion_map_kernel(
+                                               pservice->ion_client, hdl);
+                               vpu_debug(DEBUG_PPS_FILL,
+                                         "scaling list setting pps %p\n", pps);
+                               pps += pps_info_offset;
+
+                               fill_scaling_list_addr_in_pps(
+                                               data, reg, pps,
+                                               pps_info_count,
+                                               pps_info_size,
+                                               scaling_list_addr_offset);
+                       }
+               }
+
+               mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
+
+               if (!mem_region) {
+                       ion_free(pservice->ion_client, hdl);
+                       return -1;
+               }
+
+               mem_region->hdl = hdl;
+               mem_region->reg_idx = tbl[i];
+
+               if (data->mmu_dev)
+                       ret = ion_map_iommu(data->dev,
+                                           pservice->ion_client,
+                                           mem_region->hdl,
+                                           &mem_region->iova,
+                                           &mem_region->len);
+               else
+                       ret = ion_phys(pservice->ion_client,
+                                      mem_region->hdl,
+                                      (ion_phys_addr_t *)&mem_region->iova,
+                                      (size_t *)&mem_region->len);
+
+               if (ret < 0) {
+                       dev_err(pservice->dev, "reg %d fd %d ion map iommu failed\n",
+                               tbl[i], usr_fd);
+                       kfree(mem_region);
+                       ion_free(pservice->ion_client, hdl);
+                       return ret;
+               }
+
+               /*
+                * special for vpu dec num 12: record decoded length
+                * hacking for decoded length
+                * NOTE: not a perfect fix, the fd is not recorded
+                */
+               if (task->reg_len > 0 && task->reg_len == tbl[i]) {
+                       reg->dec_base = mem_region->iova + offset;
+                       vpu_debug(DEBUG_REGISTER, "dec_set %08x\n",
+                                 reg->dec_base);
+               }
+
+               reg->reg[tbl[i]] = mem_region->iova + offset;
+               INIT_LIST_HEAD(&mem_region->reg_lnk);
+               list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);
+       }
+
+       if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) {
+               for (i = 0; i < ext_inf->cnt; i++) {
+                       vpu_debug(DEBUG_IOMMU, "reg[%d] + offset %d\n",
+                                 ext_inf->elem[i].index,
+                                 ext_inf->elem[i].offset);
+                       reg->reg[ext_inf->elem[i].index] +=
+                               ext_inf->elem[i].offset;
+               }
+       }
+
+       return 0;
+}
+
+static int vcodec_reg_address_translate(struct vpu_subdev_data *data,
+                                       struct vpu_reg *reg,
+                                       struct extra_info_for_iommu *ext_inf)
+{
+       enum FORMAT_TYPE type = reg->task->get_fmt(reg->reg);
+
+       if (type < FMT_TYPE_BUTT) {
+               const struct vpu_trans_info *info = &reg->trans[type];
+               const u8 *tbl = info->table;
+               int size = info->count;
+
+               return vcodec_bufid_to_iova(data, tbl, size, reg, ext_inf);
+       }
+       pr_err("found invalid format type!\n");
+       return -1;
+}
+
+static void get_reg_freq(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+
+       if (!soc_is_rk2928g()) {
+               if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
+                       if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
+                               if (reg_probe_width(reg) > 3200) {
+                                       /*raise frequency for 4k avc.*/
+                                       reg->freq = VPU_FREQ_600M;
+                               }
+                       } else {
+                               if (reg_check_interlace(reg))
+                                       reg->freq = VPU_FREQ_400M;
+                       }
+               }
+               if (data->hw_id == HEVC_ID) {
+                       if (reg_probe_hevc_y_stride(reg) > 60000)
+                               reg->freq = VPU_FREQ_400M;
+               }
+               if (reg->type == VPU_PP)
+                       reg->freq = VPU_FREQ_400M;
+       }
+}
+
+static struct vpu_reg *reg_init(struct vpu_subdev_data *data,
+                               struct vpu_session *session,
+                               void __user *src, u32 size)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       int extra_size = 0;
+       struct extra_info_for_iommu extra_info;
+       struct vpu_reg *reg = kzalloc(sizeof(*reg) + data->reg_size,
+                                     GFP_KERNEL);
+
+       vpu_debug_enter();
+
+       if (NULL == reg) {
+               vpu_err("error: kmalloc fail in reg_init\n");
+               return NULL;
+       }
+
+       if (size > data->reg_size) {
+               pr_err("vpu reg size %u is larger than hw reg size %u\n",
+                      size, data->reg_size);
+               extra_size = size - data->reg_size;
+               size = data->reg_size;
+       }
+       reg->session = session;
+       reg->data = data;
+       reg->type = session->type;
+       reg->size = size;
+       reg->freq = VPU_FREQ_DEFAULT;
+       reg->task = &data->task_info[session->type];
+       reg->trans = data->trans_info;
+       reg->reg = (u32 *)&reg[1];
+       INIT_LIST_HEAD(&reg->session_link);
+       INIT_LIST_HEAD(&reg->status_link);
+
+       INIT_LIST_HEAD(&reg->mem_region_list);
+
+       if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {
+               vpu_err("error: copy_from_user failed in reg_init\n");
+               kfree(reg);
+               return NULL;
+       }
+
+       if (copy_from_user(&extra_info, (u8 *)src + size, extra_size)) {
+               vpu_err("error: copy_from_user failed in reg_init\n");
+               kfree(reg);
+               return NULL;
+       }
+
+       if (0 > vcodec_reg_address_translate(data, reg, &extra_info)) {
+               int i = 0;
+
+               vpu_err("error: translate reg address failed, dumping regs\n");
+               for (i = 0; i < size >> 2; i++)
+                       pr_err("reg[%02d]: %08x\n", i, *((u32 *)src + i));
+
+               kfree(reg);
+               return NULL;
+       }
+
+       mutex_lock(&pservice->lock);
+       list_add_tail(&reg->status_link, &pservice->waiting);
+       list_add_tail(&reg->session_link, &session->waiting);
+       mutex_unlock(&pservice->lock);
+
+       if (pservice->auto_freq)
+               get_reg_freq(data, reg);
+
+       vpu_debug_leave();
+       return reg;
+}
+
+static void reg_deinit(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct vcodec_mem_region *mem_region = NULL, *n;
+
+       list_del_init(&reg->session_link);
+       list_del_init(&reg->status_link);
+       if (reg == pservice->reg_codec)
+               pservice->reg_codec = NULL;
+       if (reg == pservice->reg_pproc)
+               pservice->reg_pproc = NULL;
+
+       /* release memory region attach to this registers table. */
+       list_for_each_entry_safe(mem_region, n,
+                       &reg->mem_region_list, reg_lnk) {
+               ion_free(pservice->ion_client, mem_region->hdl);
+               list_del_init(&mem_region->reg_lnk);
+               kfree(mem_region);
+       }
+
+       kfree(reg);
+}
+
+static void reg_from_wait_to_run(struct vpu_service_info *pservice,
+                                struct vpu_reg *reg)
+{
+       vpu_debug_enter();
+       list_del_init(&reg->status_link);
+       list_add_tail(&reg->status_link, &pservice->running);
+
+       list_del_init(&reg->session_link);
+       list_add_tail(&reg->session_link, &reg->session->running);
+       vpu_debug_leave();
+}
+
+static void reg_copy_from_hw(struct vpu_reg *reg, u32 *src, u32 count)
+{
+       int i;
+       u32 *dst = reg->reg;
+
+       vpu_debug_enter();
+       for (i = 0; i < count; i++, src++)
+               *dst++ = readl_relaxed(src);
+
+       dst = (u32 *)&reg->reg[0];
+       for (i = 0; i < count; i++)
+               vpu_debug(DEBUG_GET_REG, "get reg[%02d] %08x\n", i, dst[i]);
+
+       vpu_debug_leave();
+}
+
+static void reg_from_run_to_done(struct vpu_subdev_data *data,
+                                struct vpu_reg *reg)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_hw_info *hw_info = data->hw_info;
+       struct vpu_task_info *task = reg->task;
+
+       vpu_debug_enter();
+
+       list_del_init(&reg->status_link);
+       list_add_tail(&reg->status_link, &pservice->done);
+
+       list_del_init(&reg->session_link);
+       list_add_tail(&reg->session_link, &reg->session->done);
+
+       switch (reg->type) {
+       case VPU_ENC: {
+               pservice->reg_codec = NULL;
+               reg_copy_from_hw(reg, data->enc_dev.regs, hw_info->enc_reg_num);
+               reg->reg[task->reg_irq] = pservice->irq_status;
+       } break;
+       case VPU_DEC: {
+               pservice->reg_codec = NULL;
+               reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+
+               /* revert hack for decoded length */
+               if (task->reg_len > 0) {
+                       int reg_len = task->reg_len;
+                       u32 dec_get = reg->reg[reg_len];
+                       s32 dec_length = dec_get - reg->dec_base;
+
+                       vpu_debug(DEBUG_REGISTER,
+                                 "dec_get %08x dec_length %d\n",
+                                 dec_get, dec_length);
+                       reg->reg[reg_len] = dec_length << 10;
+               }
+
+               reg->reg[task->reg_irq] = pservice->irq_status;
+       } break;
+       case VPU_PP: {
+               pservice->reg_pproc = NULL;
+               reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+               writel_relaxed(0, data->dec_dev.regs + task->reg_irq);
+       } break;
+       case VPU_DEC_PP: {
+               u32 pipe_mode;
+               u32 *regs = data->dec_dev.regs;
+
+               pservice->reg_codec = NULL;
+               pservice->reg_pproc = NULL;
+
+               reg_copy_from_hw(reg, data->dec_dev.regs, hw_info->dec_reg_num);
+
+               /* NOTE: remove pp pipeline mode flag first */
+               pipe_mode = readl_relaxed(regs + task->reg_pipe);
+               pipe_mode &= ~task->pipe_mask;
+               writel_relaxed(pipe_mode, regs + task->reg_pipe);
+
+               /* revert hack for decoded length */
+               if (task->reg_len > 0) {
+                       int reg_len = task->reg_len;
+                       u32 dec_get = reg->reg[reg_len];
+                       s32 dec_length = dec_get - reg->dec_base;
+
+                       vpu_debug(DEBUG_REGISTER,
+                                 "dec_get %08x dec_length %d\n",
+                                 dec_get, dec_length);
+                       reg->reg[reg_len] = dec_length << 10;
+               }
+
+               reg->reg[task->reg_irq] = pservice->irq_status;
+       } break;
+       default: {
+               vpu_err("error: copy reg from hw with unknown type %d\n",
+                       reg->type);
+       } break;
+       }
+       vcodec_exit_mode(data);
+
+       atomic_sub(1, &reg->session->task_running);
+       atomic_sub(1, &pservice->total_running);
+       wake_up(&reg->session->wait);
+
+       vpu_debug_leave();
+}
+
+static void vpu_service_set_freq(struct vpu_service_info *pservice,
+                                struct vpu_reg *reg)
+{
+       enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
+
+       if (curr == reg->freq)
+               return;
+
+       atomic_set(&pservice->freq_status, reg->freq);
+       switch (reg->freq) {
+       case VPU_FREQ_200M: {
+               clk_set_rate(pservice->aclk_vcodec, 200*MHZ);
+       } break;
+       case VPU_FREQ_266M: {
+               clk_set_rate(pservice->aclk_vcodec, 266*MHZ);
+       } break;
+       case VPU_FREQ_300M: {
+               clk_set_rate(pservice->aclk_vcodec, 300*MHZ);
+       } break;
+       case VPU_FREQ_400M: {
+               clk_set_rate(pservice->aclk_vcodec, 400*MHZ);
+       } break;
+       case VPU_FREQ_500M: {
+               clk_set_rate(pservice->aclk_vcodec, 500*MHZ);
+       } break;
+       case VPU_FREQ_600M: {
+               clk_set_rate(pservice->aclk_vcodec, 600*MHZ);
+       } break;
+       default: {
+               unsigned long rate = 300*MHZ;
+
+               if (soc_is_rk2928g())
+                       rate = 400*MHZ;
+
+               clk_set_rate(pservice->aclk_vcodec, rate);
+       } break;
+       }
+}
+
+static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_task_info *task = reg->task;
+       struct vpu_hw_info *hw_info = data->hw_info;
+       int i;
+       u32 *src = (u32 *)&reg->reg[0];
+       u32 enable_mask = task->enable_mask;
+       u32 gating_mask = task->gating_mask;
+       u32 reg_en = task->reg_en;
+
+       vpu_debug_enter();
+
+       atomic_add(1, &pservice->total_running);
+       atomic_add(1, &reg->session->task_running);
+
+       if (pservice->auto_freq)
+               vpu_service_set_freq(pservice, reg);
+
+       vcodec_enter_mode(data);
+
+       switch (reg->type) {
+       case VPU_ENC: {
+               u32 *dst = data->enc_dev.regs;
+               u32 base = 0;
+               u32 end  = hw_info->enc_reg_num;
+               /* u32 reg_gating = task->reg_gating; */
+
+               pservice->reg_codec = reg;
+
+               vpu_debug(DEBUG_TASK_INFO, "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+                         base, end, reg_en, enable_mask, gating_mask);
+
+               VEPU_CLEAN_CACHE(dst);
+
+               if (debug & DEBUG_SET_REG)
+                       for (i = base; i < end; i++)
+                               vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+                                         i, src[i]);
+
+               /*
+                * NOTE: encoder need to setup mode first
+                */
+               writel_relaxed(src[reg_en] & enable_mask, dst + reg_en);
+
+               /* NOTE: encoder gating is not on enable register */
+               /* src[reg_gating] |= gating_mask; */
+
+               for (i = base; i < end; i++) {
+                       if (i != reg_en)
+                               writel_relaxed(src[i], dst + i);
+               }
+
+               writel(src[reg_en], dst + reg_en);
+               dsb(sy);
+
+               time_record(reg->task, 0);
+       } break;
+       case VPU_DEC: {
+               u32 *dst = data->dec_dev.regs;
+               u32 len = hw_info->dec_reg_num;
+               u32 base = hw_info->base_dec;
+               u32 end  = hw_info->end_dec;
+
+               pservice->reg_codec = reg;
+
+               vpu_debug(DEBUG_TASK_INFO, "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+                         base, end, reg_en, enable_mask, gating_mask);
+
+               VDPU_CLEAN_CACHE(dst);
+
+               /* on rkvdec set cache size to 64byte */
+               if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
+                       u32 *cache_base = dst + 0x100;
+                       u32 val = (debug & DEBUG_CACHE_32B) ? (0x3) : (0x13);
+                       writel_relaxed(val, cache_base + 0x07);
+                       writel_relaxed(val, cache_base + 0x17);
+               }
+
+               if (debug & DEBUG_SET_REG)
+                       for (i = 0; i < len; i++)
+                               vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+                                         i, src[i]);
+
+               /*
+                * NOTE: The end register is invalid. Do NOT write to it
+                *       Also the base register must be written
+                */
+               for (i = base; i < end; i++) {
+                       if (i != reg_en)
+                               writel_relaxed(src[i], dst + i);
+               }
+
+               writel(src[reg_en] | gating_mask, dst + reg_en);
+               dsb(sy);
+
+               time_record(reg->task, 0);
+       } break;
+       case VPU_PP: {
+               u32 *dst = data->dec_dev.regs;
+               u32 base = hw_info->base_pp;
+               u32 end  = hw_info->end_pp;
+
+               pservice->reg_pproc = reg;
+
+               vpu_debug(DEBUG_TASK_INFO, "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+                         base, end, reg_en, enable_mask, gating_mask);
+
+               if (debug & DEBUG_SET_REG)
+                       for (i = base; i < end; i++)
+                               vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+                                         i, src[i]);
+
+               for (i = base; i < end; i++) {
+                       if (i != reg_en)
+                               writel_relaxed(src[i], dst + i);
+               }
+
+               writel(src[reg_en] | gating_mask, dst + reg_en);
+               dsb(sy);
+
+               time_record(reg->task, 0);
+       } break;
+       case VPU_DEC_PP: {
+               u32 *dst = data->dec_dev.regs;
+               u32 base = hw_info->base_dec_pp;
+               u32 end  = hw_info->end_dec_pp;
+
+               pservice->reg_codec = reg;
+               pservice->reg_pproc = reg;
+
+               vpu_debug(DEBUG_TASK_INFO, "reg: base %3d end %d en %2d mask: en %x gate %x\n",
+                         base, end, reg_en, enable_mask, gating_mask);
+
+               /* VDPU_SOFT_RESET(dst); */
+               VDPU_CLEAN_CACHE(dst);
+
+               if (debug & DEBUG_SET_REG)
+                       for (i = base; i < end; i++)
+                               vpu_debug(DEBUG_SET_REG, "set reg[%02d] %08x\n",
+                                         i, src[i]);
+
+               for (i = base; i < end; i++) {
+                       if (i != reg_en)
+                               writel_relaxed(src[i], dst + i);
+               }
+
+               /* NOTE: dec output must be disabled */
+
+               writel(src[reg_en] | gating_mask, dst + reg_en);
+               dsb(sy);
+
+               time_record(reg->task, 0);
+       } break;
+       default: {
+               vpu_err("error: unsupport session type %d", reg->type);
+               atomic_sub(1, &pservice->total_running);
+               atomic_sub(1, &reg->session->task_running);
+       } break;
+       }
+
+       vpu_debug_leave();
+}
+
+static void try_set_reg(struct vpu_subdev_data *data)
+{
+       struct vpu_service_info *pservice = data->pservice;
+
+       vpu_debug_enter();
+       if (!list_empty(&pservice->waiting)) {
+               struct vpu_reg *reg_codec = pservice->reg_codec;
+               struct vpu_reg *reg_pproc = pservice->reg_pproc;
+               int can_set = 0;
+               bool change_able = (reg_codec == NULL) && (reg_pproc == NULL);
+               int reset_request = atomic_read(&pservice->reset_request);
+               struct vpu_reg *reg = list_entry(pservice->waiting.next,
+                               struct vpu_reg, status_link);
+
+               vpu_service_power_on(pservice);
+
+               if (change_able || !reset_request) {
+                       switch (reg->type) {
+                       case VPU_ENC: {
+                               if (change_able)
+                                       can_set = 1;
+                       } break;
+                       case VPU_DEC: {
+                               if (reg_codec == NULL)
+                                       can_set = 1;
+                               if (pservice->auto_freq && (reg_pproc != NULL))
+                                       can_set = 0;
+                       } break;
+                       case VPU_PP: {
+                               if (reg_codec == NULL) {
+                                       if (reg_pproc == NULL)
+                                               can_set = 1;
+                               } else {
+                                       if ((reg_codec->type == VPU_DEC) &&
+                                           (reg_pproc == NULL))
+                                               can_set = 1;
+
+                                       /*
+                                        * NOTE:
+                                        * can not charge frequency
+                                        * when vpu is working
+                                        */
+                                       if (pservice->auto_freq)
+                                               can_set = 0;
+                               }
+                       } break;
+                       case VPU_DEC_PP: {
+                               if (change_able)
+                                       can_set = 1;
+                               } break;
+                       default: {
+                               pr_err("undefined reg type %d\n", reg->type);
+                       } break;
+                       }
+               }
+
+               /* then check reset request */
+               if (reset_request && !change_able)
+                       reset_request = 0;
+
+               /* do reset before setting registers */
+               if (reset_request)
+                       vpu_reset(data);
+
+               if (can_set) {
+                       reg_from_wait_to_run(pservice, reg);
+                       reg_copy_to_hw(reg->data, reg);
+               }
+       }
+       vpu_debug_leave();
+}
+
+static int return_reg(struct vpu_subdev_data *data,
+                     struct vpu_reg *reg, u32 __user *dst)
+{
+       struct vpu_hw_info *hw_info = data->hw_info;
+       size_t size = reg->size;
+       u32 base;
+
+       vpu_debug_enter();
+       switch (reg->type) {
+       case VPU_ENC: {
+               base = 0;
+       } break;
+       case VPU_DEC: {
+               base = hw_info->base_dec_pp;
+       } break;
+       case VPU_PP: {
+               base = hw_info->base_pp;
+       } break;
+       case VPU_DEC_PP: {
+               base = hw_info->base_dec_pp;
+       } break;
+       default: {
+               vpu_err("error: copy reg to user with unknown type %d\n",
+                       reg->type);
+               return -EFAULT;
+       } break;
+       }
+
+       if (copy_to_user(dst, &reg->reg[base], size)) {
+               vpu_err("error: return_reg copy_to_user failed\n");
+               return -EFAULT;
+       }
+
+       reg_deinit(data, reg);
+       vpu_debug_leave();
+       return 0;
+}
+
+static long vpu_service_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+{
+       struct vpu_subdev_data *data =
+               container_of(filp->f_path.dentry->d_inode->i_cdev,
+                            struct vpu_subdev_data, cdev);
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+       vpu_debug_enter();
+       if (NULL == session)
+               return -EINVAL;
+
+       switch (cmd) {
+       case VPU_IOC_SET_CLIENT_TYPE: {
+               session->type = (enum VPU_CLIENT_TYPE)arg;
+               vpu_debug(DEBUG_IOCTL, "pid %d set client type %d\n",
+                         session->pid, session->type);
+       } break;
+       case VPU_IOC_GET_HW_FUSE_STATUS: {
+               struct vpu_request req;
+
+               vpu_debug(DEBUG_IOCTL, "pid %d get hw status %d\n",
+                         session->pid, session->type);
+               if (copy_from_user(&req, (void __user *)arg, sizeof(req))) {
+                       vpu_err("error: get hw status copy_from_user failed\n");
+                       return -EFAULT;
+               } else {
+                       void *config = (session->type != VPU_ENC) ?
+                                      ((void *)&pservice->dec_config) :
+                                      ((void *)&pservice->enc_config);
+                       size_t size = (session->type != VPU_ENC) ?
+                                     (sizeof(struct vpu_dec_config)) :
+                                     (sizeof(struct vpu_enc_config));
+                       if (copy_to_user((void __user *)req.req,
+                                        config, size)) {
+                               vpu_err("error: get hw status copy_to_user failed type %d\n",
+                                       session->type);
+                               return -EFAULT;
+                       }
+               }
+       } break;
+       case VPU_IOC_SET_REG: {
+               struct vpu_request req;
+               struct vpu_reg *reg;
+
+               vpu_debug(DEBUG_IOCTL, "pid %d set reg type %d\n",
+                         session->pid, session->type);
+               if (copy_from_user(&req, (void __user *)arg,
+                                  sizeof(struct vpu_request))) {
+                       vpu_err("error: set reg copy_from_user failed\n");
+                       return -EFAULT;
+               }
+               reg = reg_init(data, session, (void __user *)req.req, req.size);
+               if (NULL == reg) {
+                       return -EFAULT;
+               } else {
+                       mutex_lock(&pservice->lock);
+                       try_set_reg(data);
+                       mutex_unlock(&pservice->lock);
+               }
+       } break;
+       case VPU_IOC_GET_REG: {
+               struct vpu_request req;
+               struct vpu_reg *reg;
+               int ret;
+
+               vpu_debug(DEBUG_IOCTL, "pid %d get reg type %d\n",
+                         session->pid, session->type);
+               if (copy_from_user(&req, (void __user *)arg,
+                                  sizeof(struct vpu_request))) {
+                       vpu_err("error: get reg copy_from_user failed\n");
+                       return -EFAULT;
+               }
+
+               ret = wait_event_timeout(session->wait,
+                                        !list_empty(&session->done),
+                                        VPU_TIMEOUT_DELAY);
+
+               if (!list_empty(&session->done)) {
+                       if (ret < 0)
+                               vpu_err("warning: pid %d wait task error ret %d\n",
+                                       session->pid, ret);
+                       ret = 0;
+               } else {
+                       if (unlikely(ret < 0)) {
+                               vpu_err("error: pid %d wait task ret %d\n",
+                                       session->pid, ret);
+                       } else if (ret == 0) {
+                               vpu_err("error: pid %d wait %d task done timeout\n",
+                                       session->pid,
+                                       atomic_read(&session->task_running));
+                               ret = -ETIMEDOUT;
+                       }
+               }
+
+               if (ret < 0) {
+                       int task_running = atomic_read(&session->task_running);
+
+                       mutex_lock(&pservice->lock);
+                       vpu_service_dump(pservice);
+                       if (task_running) {
+                               atomic_set(&session->task_running, 0);
+                               atomic_sub(task_running,
+                                          &pservice->total_running);
+                               pr_err("%d task is running but not return, reset hardware...",
+                                      task_running);
+                               vpu_reset(data);
+                               pr_err("done\n");
+                       }
+                       vpu_service_session_clear(data, session);
+                       mutex_unlock(&pservice->lock);
+                       return ret;
+               }
+
+               mutex_lock(&pservice->lock);
+               reg = list_entry(session->done.next,
+                                struct vpu_reg, session_link);
+               return_reg(data, reg, (u32 __user *)req.req);
+               mutex_unlock(&pservice->lock);
+       } break;
+       case VPU_IOC_PROBE_IOMMU_STATUS: {
+               int iommu_enable = 1;
+
+               vpu_debug(DEBUG_IOCTL, "VPU_IOC_PROBE_IOMMU_STATUS\n");
+
+               if (copy_to_user((void __user *)arg,
+                                &iommu_enable, sizeof(int))) {
+                       vpu_err("error: iommu status copy_to_user failed\n");
+                       return -EFAULT;
+               }
+       } break;
+       default: {
+               vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
+       } break;
+       }
+       vpu_debug_leave();
+       return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long compat_vpu_service_ioctl(struct file *filp, unsigned int cmd,
+                                    unsigned long arg)
+{
+       struct vpu_subdev_data *data =
+               container_of(filp->f_path.dentry->d_inode->i_cdev,
+                            struct vpu_subdev_data, cdev);
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+       vpu_debug_enter();
+       vpu_debug(3, "cmd %x, COMPAT_VPU_IOC_SET_CLIENT_TYPE %x\n", cmd,
+                 (u32)COMPAT_VPU_IOC_SET_CLIENT_TYPE);
+       if (NULL == session)
+               return -EINVAL;
+
+       switch (cmd) {
+       case COMPAT_VPU_IOC_SET_CLIENT_TYPE: {
+               session->type = (enum VPU_CLIENT_TYPE)arg;
+               vpu_debug(DEBUG_IOCTL, "compat set client type %d\n",
+                         session->type);
+       } break;
+       case COMPAT_VPU_IOC_GET_HW_FUSE_STATUS: {
+               struct compat_vpu_request req;
+
+               vpu_debug(DEBUG_IOCTL, "compat get hw status %d\n",
+                         session->type);
+               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
+                                  sizeof(struct compat_vpu_request))) {
+                       vpu_err("error: compat get hw status copy_from_user failed\n");
+                       return -EFAULT;
+               } else {
+                       void *config = (session->type != VPU_ENC) ?
+                                      ((void *)&pservice->dec_config) :
+                                      ((void *)&pservice->enc_config);
+                       size_t size = (session->type != VPU_ENC) ?
+                                     (sizeof(struct vpu_dec_config)) :
+                                     (sizeof(struct vpu_enc_config));
+
+                       if (copy_to_user(compat_ptr((compat_uptr_t)req.req),
+                                        config, size)) {
+                               vpu_err("error: compat get hw status copy_to_user failed type %d\n",
+                                       session->type);
+                               return -EFAULT;
+                       }
+               }
+       } break;
+       case COMPAT_VPU_IOC_SET_REG: {
+               struct compat_vpu_request req;
+               struct vpu_reg *reg;
+
+               vpu_debug(DEBUG_IOCTL, "compat set reg type %d\n",
+                         session->type);
+               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
+                                  sizeof(struct compat_vpu_request))) {
+                       vpu_err("compat set_reg copy_from_user failed\n");
+                       return -EFAULT;
+               }
+               reg = reg_init(data, session,
+                              compat_ptr((compat_uptr_t)req.req), req.size);
+               if (NULL == reg) {
+                       return -EFAULT;
+               } else {
+                       mutex_lock(&pservice->lock);
+                       try_set_reg(data);
+                       mutex_unlock(&pservice->lock);
+               }
+       } break;
+       case COMPAT_VPU_IOC_GET_REG: {
+               struct compat_vpu_request req;
+               struct vpu_reg *reg;
+               int ret;
+
+               vpu_debug(DEBUG_IOCTL, "compat get reg type %d\n",
+                         session->type);
+               if (copy_from_user(&req, compat_ptr((compat_uptr_t)arg),
+                                  sizeof(struct compat_vpu_request))) {
+                       vpu_err("compat get reg copy_from_user failed\n");
+                       return -EFAULT;
+               }
+
+               ret = wait_event_timeout(session->wait,
+                                        !list_empty(&session->done),
+                                        VPU_TIMEOUT_DELAY);
+
+               if (!list_empty(&session->done)) {
+                       if (ret < 0)
+                               vpu_err("warning: pid %d wait task error ret %d\n",
+                                       session->pid, ret);
+                       ret = 0;
+               } else {
+                       if (unlikely(ret < 0)) {
+                               vpu_err("error: pid %d wait task ret %d\n",
+                                       session->pid, ret);
+                       } else if (ret == 0) {
+                               vpu_err("error: pid %d wait %d task done timeout\n",
+                                       session->pid,
+                                       atomic_read(&session->task_running));
+                               ret = -ETIMEDOUT;
+                       }
+               }
+
+               if (ret < 0) {
+                       int task_running = atomic_read(&session->task_running);
+
+                       mutex_lock(&pservice->lock);
+                       vpu_service_dump(pservice);
+                       if (task_running) {
+                               atomic_set(&session->task_running, 0);
+                               atomic_sub(task_running,
+                                          &pservice->total_running);
+                               pr_err("%d task is running but not return, reset hardware...",
+                                      task_running);
+                               vpu_reset(data);
+                               pr_err("done\n");
+                       }
+                       vpu_service_session_clear(data, session);
+                       mutex_unlock(&pservice->lock);
+                       return ret;
+               }
+
+               mutex_lock(&pservice->lock);
+               reg = list_entry(session->done.next,
+                                struct vpu_reg, session_link);
+               return_reg(data, reg, compat_ptr((compat_uptr_t)req.req));
+               mutex_unlock(&pservice->lock);
+       } break;
+       case COMPAT_VPU_IOC_PROBE_IOMMU_STATUS: {
+               int iommu_enable = 1;
+
+               vpu_debug(DEBUG_IOCTL, "COMPAT_VPU_IOC_PROBE_IOMMU_STATUS\n");
+
+               if (copy_to_user(compat_ptr((compat_uptr_t)arg),
+                                &iommu_enable, sizeof(int))) {
+                       vpu_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n");
+                       return -EFAULT;
+               }
+       } break;
+       default: {
+               vpu_err("error: unknow vpu service ioctl cmd %x\n", cmd);
+       } break;
+       }
+       vpu_debug_leave();
+       return 0;
+}
+#endif
+
+static int vpu_service_check_hw(struct vpu_subdev_data *data)
+{
+       int ret = -EINVAL, i = 0;
+       u32 hw_id = readl_relaxed(data->regs);
+
+       hw_id = (hw_id >> 16) & 0xFFFF;
+       pr_info("checking hw id %x\n", hw_id);
+       data->hw_info = NULL;
+       for (i = 0; i < ARRAY_SIZE(vcodec_info_set); i++) {
+               struct vcodec_info *info = &vcodec_info_set[i];
+
+               if (hw_id == info->hw_id) {
+                       data->hw_id = info->hw_id;
+                       data->hw_info = info->hw_info;
+                       data->task_info = info->task_info;
+                       data->trans_info = info->trans_info;
+                       ret = 0;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int vpu_service_open(struct inode *inode, struct file *filp)
+{
+       struct vpu_subdev_data *data = container_of(
+                       inode->i_cdev, struct vpu_subdev_data, cdev);
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_session *session = kmalloc(sizeof(*session), GFP_KERNEL);
+
+       vpu_debug_enter();
+
+       if (NULL == session) {
+               vpu_err("error: unable to allocate memory for vpu_session.");
+               return -ENOMEM;
+       }
+
+       session->type   = VPU_TYPE_BUTT;
+       session->pid    = current->pid;
+       INIT_LIST_HEAD(&session->waiting);
+       INIT_LIST_HEAD(&session->running);
+       INIT_LIST_HEAD(&session->done);
+       INIT_LIST_HEAD(&session->list_session);
+       init_waitqueue_head(&session->wait);
+       atomic_set(&session->task_running, 0);
+       mutex_lock(&pservice->lock);
+       list_add_tail(&session->list_session, &pservice->session);
+       filp->private_data = (void *)session;
+       mutex_unlock(&pservice->lock);
+
+       pr_debug("dev opened\n");
+       vpu_debug_leave();
+       return nonseekable_open(inode, filp);
+}
+
+static int vpu_service_release(struct inode *inode, struct file *filp)
+{
+       struct vpu_subdev_data *data = container_of(
+                       inode->i_cdev, struct vpu_subdev_data, cdev);
+       struct vpu_service_info *pservice = data->pservice;
+       int task_running;
+       struct vpu_session *session = (struct vpu_session *)filp->private_data;
+
+       vpu_debug_enter();
+       if (NULL == session)
+               return -EINVAL;
+
+       task_running = atomic_read(&session->task_running);
+       if (task_running) {
+               pr_err("error: session %d still has %d task running when closing\n",
+                      session->pid, task_running);
+               msleep(50);
+       }
+       wake_up(&session->wait);
+
+       mutex_lock(&pservice->lock);
+       /* remove this filp from the asynchronusly notified filp's */
+       list_del_init(&session->list_session);
+       vpu_service_session_clear(data, session);
+       kfree(session);
+       filp->private_data = NULL;
+       mutex_unlock(&pservice->lock);
+
+       pr_debug("dev closed\n");
+       vpu_debug_leave();
+       return 0;
+}
+
+static const struct file_operations vpu_service_fops = {
+       .unlocked_ioctl = vpu_service_ioctl,
+       .open           = vpu_service_open,
+       .release        = vpu_service_release,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = compat_vpu_service_ioctl,
+#endif
+};
+
+static irqreturn_t vdpu_irq(int irq, void *dev_id);
+static irqreturn_t vdpu_isr(int irq, void *dev_id);
+static irqreturn_t vepu_irq(int irq, void *dev_id);
+static irqreturn_t vepu_isr(int irq, void *dev_id);
+static void get_hw_info(struct vpu_subdev_data *data);
+
+static struct device *rockchip_get_sysmmu_dev(const char *compt)
+{
+       struct device_node *dn = NULL;
+       struct platform_device *pd = NULL;
+       struct device *ret = NULL;
+
+       dn = of_find_compatible_node(NULL, NULL, compt);
+       if (!dn) {
+               pr_err("can't find device node %s \r\n", compt);
+               return NULL;
+       }
+
+       pd = of_find_device_by_node(dn);
+       if (!pd) {
+               pr_err("can't find platform device in device node %s\n", compt);
+               return  NULL;
+       }
+       ret = &pd->dev;
+
+       return ret;
+}
+
+#ifdef CONFIG_IOMMU_API
+static inline void platform_set_sysmmu(struct device *iommu,
+                                      struct device *dev)
+{
+       dev->archdata.iommu = iommu;
+}
+#else
+static inline void platform_set_sysmmu(struct device *iommu,
+                                      struct device *dev)
+{
+}
+#endif
+
+int vcodec_sysmmu_fault_hdl(struct device *dev,
+                           enum rk_iommu_inttype itype,
+                           unsigned long pgtable_base,
+                           unsigned long fault_addr, unsigned int status)
+{
+       struct platform_device *pdev;
+       struct vpu_service_info *pservice;
+       struct vpu_subdev_data *data;
+
+       vpu_debug_enter();
+
+       if (dev == NULL) {
+               pr_err("invalid NULL dev\n");
+               return 0;
+       }
+
+       pdev = container_of(dev, struct platform_device, dev);
+       if (pdev == NULL) {
+               pr_err("invalid NULL platform_device\n");
+               return 0;
+       }
+
+       data = platform_get_drvdata(pdev);
+       if (data == NULL) {
+               pr_err("invalid NULL vpu_subdev_data\n");
+               return 0;
+       }
+
+       pservice = data->pservice;
+       if (pservice == NULL) {
+               pr_err("invalid NULL vpu_service_info\n");
+               return 0;
+       }
+
+       if (pservice->reg_codec) {
+               struct vpu_reg *reg = pservice->reg_codec;
+               struct vcodec_mem_region *mem, *n;
+               int i = 0;
+
+               pr_err("vcodec, fault addr 0x%08lx\n", fault_addr);
+               if (!list_empty(&reg->mem_region_list)) {
+                       list_for_each_entry_safe(mem, n, &reg->mem_region_list,
+                                                reg_lnk) {
+                               pr_err("vcodec, reg[%02u] mem region [%02d] 0x%lx %lx\n",
+                                      mem->reg_idx, i, mem->iova, mem->len);
+                               i++;
+                       }
+               } else {
+                       pr_err("no memory region mapped\n");
+               }
+
+               if (reg->data) {
+                       struct vpu_subdev_data *data = reg->data;
+                       u32 *base = (u32 *)data->dec_dev.regs;
+                       u32 len = data->hw_info->dec_reg_num;
+
+                       pr_err("current errror register set:\n");
+
+                       for (i = 0; i < len; i++)
+                               pr_err("reg[%02d] %08x\n",
+                                      i, readl_relaxed(base + i));
+               }
+
+               pr_alert("vcodec, page fault occur, reset hw\n");
+
+               /* reg->reg[101] = 1; */
+               vpu_reset(data);
+       }
+
+       return 0;
+}
+
+static int vcodec_subdev_probe(struct platform_device *pdev,
+                              struct vpu_service_info *pservice)
+{
+       int ret = 0;
+       struct resource *res = NULL;
+       u32 ioaddr = 0;
+       u8 *regs = NULL;
+       struct vpu_hw_info *hw_info = NULL;
+       struct device *dev = &pdev->dev;
+       char *name = (char *)dev_name(dev);
+       struct device_node *np = pdev->dev.of_node;
+       struct vpu_subdev_data *data =
+               devm_kzalloc(dev, sizeof(struct vpu_subdev_data), GFP_KERNEL);
+       u32 iommu_en = 0;
+       char mmu_dev_dts_name[40];
+
+       of_property_read_u32(np, "iommu_enabled", &iommu_en);
+
+       pr_info("probe device %s\n", dev_name(dev));
+
+       data->pservice = pservice;
+       data->dev = dev;
+
+       of_property_read_string(np, "name", (const char **)&name);
+       of_property_read_u32(np, "dev_mode", (u32 *)&data->mode);
+
+       if (pservice->reg_base == 0) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               data->regs = devm_ioremap_resource(dev, res);
+               if (IS_ERR(data->regs)) {
+                       ret = PTR_ERR(data->regs);
+                       goto err;
+               }
+               ioaddr = res->start;
+       } else {
+               data->regs = pservice->reg_base;
+               ioaddr = pservice->ioaddr;
+       }
+
+       clear_bit(MMU_ACTIVATED, &data->state);
+       vcodec_enter_mode(data);
+       ret = vpu_service_check_hw(data);
+       if (ret < 0) {
+               vpu_err("error: hw info check faild\n");
+               goto err;
+       }
+
+       hw_info = data->hw_info;
+       regs = (u8 *)data->regs;
+
+       if (hw_info->dec_reg_num) {
+               data->dec_dev.iosize = hw_info->dec_io_size;
+               data->dec_dev.regs = (u32 *)(regs + hw_info->dec_offset);
+       }
+
+       if (hw_info->enc_reg_num) {
+               data->enc_dev.iosize = hw_info->enc_io_size;
+               data->enc_dev.regs = (u32 *)(regs + hw_info->enc_offset);
+       }
+
+       data->reg_size = max(hw_info->dec_io_size, hw_info->enc_io_size);
+
+       data->irq_enc = platform_get_irq_byname(pdev, "irq_enc");
+       if (data->irq_enc > 0) {
+               ret = devm_request_threaded_irq(dev, data->irq_enc,
+                                               vepu_irq, vepu_isr,
+                                               IRQF_SHARED, dev_name(dev),
+                                               (void *)data);
+               if (ret) {
+                       dev_err(dev, "error: can't request vepu irq %d\n",
+                               data->irq_enc);
+                       goto err;
+               }
+       }
+       data->irq_dec = platform_get_irq_byname(pdev, "irq_dec");
+       if (data->irq_dec > 0) {
+               ret = devm_request_threaded_irq(dev, data->irq_dec,
+                                               vdpu_irq, vdpu_isr,
+                                               IRQF_SHARED, dev_name(dev),
+                                               (void *)data);
+               if (ret) {
+                       dev_err(dev, "error: can't request vdpu irq %d\n",
+                               data->irq_dec);
+                       goto err;
+               }
+       }
+       atomic_set(&data->dec_dev.irq_count_codec, 0);
+       atomic_set(&data->dec_dev.irq_count_pp, 0);
+       atomic_set(&data->enc_dev.irq_count_codec, 0);
+       atomic_set(&data->enc_dev.irq_count_pp, 0);
+
+       if (iommu_en) {
+               if (data->mode == VCODEC_RUNNING_MODE_HEVC)
+                       sprintf(mmu_dev_dts_name,
+                               HEVC_IOMMU_COMPATIBLE_NAME);
+               else if (data->mode == VCODEC_RUNNING_MODE_VPU)
+                       sprintf(mmu_dev_dts_name,
+                               VPU_IOMMU_COMPATIBLE_NAME);
+               else if (data->mode == VCODEC_RUNNING_MODE_RKVDEC)
+                       sprintf(mmu_dev_dts_name, VDEC_IOMMU_COMPATIBLE_NAME);
+               else
+                       sprintf(mmu_dev_dts_name,
+                               HEVC_IOMMU_COMPATIBLE_NAME);
+
+               data->mmu_dev =
+                       rockchip_get_sysmmu_dev(mmu_dev_dts_name);
+
+               if (data->mmu_dev)
+                       platform_set_sysmmu(data->mmu_dev, dev);
+
+               rockchip_iovmm_set_fault_handler(dev, vcodec_sysmmu_fault_hdl);
+       }
+
+       get_hw_info(data);
+       pservice->auto_freq = true;
+
+       vcodec_exit_mode(data);
+       /* create device node */
+       ret = alloc_chrdev_region(&data->dev_t, 0, 1, name);
+       if (ret) {
+               dev_err(dev, "alloc dev_t failed\n");
+               goto err;
+       }
+
+       cdev_init(&data->cdev, &vpu_service_fops);
+
+       data->cdev.owner = THIS_MODULE;
+       data->cdev.ops = &vpu_service_fops;
+
+       ret = cdev_add(&data->cdev, data->dev_t, 1);
+
+       if (ret) {
+               dev_err(dev, "add dev_t failed\n");
+               goto err;
+       }
+
+       data->cls = class_create(THIS_MODULE, name);
+
+       if (IS_ERR(data->cls)) {
+               ret = PTR_ERR(data->cls);
+               dev_err(dev, "class_create err:%d\n", ret);
+               goto err;
+       }
+
+       data->child_dev = device_create(data->cls, dev,
+               data->dev_t, NULL, name);
+
+       platform_set_drvdata(pdev, data);
+
+       INIT_LIST_HEAD(&data->lnk_service);
+       list_add_tail(&data->lnk_service, &pservice->subdev_list);
+
+#ifdef CONFIG_DEBUG_FS
+       data->debugfs_dir = vcodec_debugfs_create_device_dir(name, parent);
+       if (!IS_ERR_OR_NULL(data->debugfs_dir))
+               data->debugfs_file_regs =
+                       debugfs_create_file("regs", 0664, data->debugfs_dir,
+                                       data, &debug_vcodec_fops);
+       else
+               vpu_err("create debugfs dir %s failed\n", name);
+#endif
+       return 0;
+err:
+       if (data->child_dev) {
+               device_destroy(data->cls, data->dev_t);
+               cdev_del(&data->cdev);
+               unregister_chrdev_region(data->dev_t, 1);
+       }
+
+       if (data->cls)
+               class_destroy(data->cls);
+       return -1;
+}
+
+static void vcodec_subdev_remove(struct vpu_subdev_data *data)
+{
+       struct vpu_service_info *pservice = data->pservice;
+
+       mutex_lock(&pservice->lock);
+       cancel_delayed_work_sync(&pservice->power_off_work);
+       vpu_service_power_off(pservice);
+       mutex_unlock(&pservice->lock);
+
+       device_destroy(data->cls, data->dev_t);
+       class_destroy(data->cls);
+       cdev_del(&data->cdev);
+       unregister_chrdev_region(data->dev_t, 1);
+
+#ifdef CONFIG_DEBUG_FS
+       if (!IS_ERR_OR_NULL(data->debugfs_dir))
+               debugfs_remove_recursive(data->debugfs_dir);
+#endif
+}
+
+static void vcodec_read_property(struct device_node *np,
+                                struct vpu_service_info *pservice)
+{
+       pservice->mode_bit = 0;
+       pservice->mode_ctrl = 0;
+       pservice->subcnt = 0;
+       pservice->grf_base = NULL;
+
+       of_property_read_u32(np, "subcnt", &pservice->subcnt);
+
+       if (pservice->subcnt > 1) {
+               of_property_read_u32(np, "mode_bit", &pservice->mode_bit);
+               of_property_read_u32(np, "mode_ctrl", &pservice->mode_ctrl);
+       }
+#ifdef CONFIG_MFD_SYSCON
+       pservice->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+       if (IS_ERR_OR_NULL(pservice->grf)) {
+               pservice->grf = NULL;
+#ifdef CONFIG_ARM
+               pservice->grf_base = RK_GRF_VIRT;
+#else
+               vpu_err("can't find vpu grf property\n");
+               return;
+#endif
+       }
+#else
+#ifdef CONFIG_ARM
+       pservice->grf_base = RK_GRF_VIRT;
+#else
+       vpu_err("can't find vpu grf property\n");
+       return;
+#endif
+#endif
+
+#ifdef CONFIG_RESET_CONTROLLER
+       pservice->rst_a = devm_reset_control_get(pservice->dev, "video_a");
+       pservice->rst_h = devm_reset_control_get(pservice->dev, "video_h");
+       pservice->rst_v = devm_reset_control_get(pservice->dev, "video");
+
+       if (IS_ERR_OR_NULL(pservice->rst_a)) {
+               pr_warn("No aclk reset resource define\n");
+               pservice->rst_a = NULL;
+       }
+
+       if (IS_ERR_OR_NULL(pservice->rst_h)) {
+               pr_warn("No hclk reset resource define\n");
+               pservice->rst_h = NULL;
+       }
+
+       if (IS_ERR_OR_NULL(pservice->rst_v)) {
+               pr_warn("No core reset resource define\n");
+               pservice->rst_v = NULL;
+       }
+#endif
+
+       of_property_read_string(np, "name", (const char **)&pservice->name);
+}
+
+static void vcodec_init_drvdata(struct vpu_service_info *pservice)
+{
+       pservice->dev_id = VCODEC_DEVICE_ID_VPU;
+       pservice->curr_mode = -1;
+
+       wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu");
+       INIT_LIST_HEAD(&pservice->waiting);
+       INIT_LIST_HEAD(&pservice->running);
+       mutex_init(&pservice->lock);
+
+       INIT_LIST_HEAD(&pservice->done);
+       INIT_LIST_HEAD(&pservice->session);
+       INIT_LIST_HEAD(&pservice->subdev_list);
+
+       pservice->reg_pproc     = NULL;
+       atomic_set(&pservice->total_running, 0);
+       atomic_set(&pservice->enabled,       0);
+       atomic_set(&pservice->power_on_cnt,  0);
+       atomic_set(&pservice->power_off_cnt, 0);
+       atomic_set(&pservice->reset_request, 0);
+
+       INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);
+
+       pservice->ion_client = rockchip_ion_client_create("vpu");
+       if (IS_ERR(pservice->ion_client)) {
+               vpu_err("failed to create ion client for vcodec ret %ld\n",
+                       PTR_ERR(pservice->ion_client));
+       } else {
+               vpu_debug(DEBUG_IOMMU, "vcodec ion client create success!\n");
+       }
+}
+
+static int vcodec_probe(struct platform_device *pdev)
+{
+       int i;
+       int ret = 0;
+       struct resource *res = NULL;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct vpu_service_info *pservice =
+               devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL);
+
+       pservice->dev = dev;
+
+       vcodec_read_property(np, pservice);
+       vcodec_init_drvdata(pservice);
+
+       if (strncmp(pservice->name, "hevc_service", 12) == 0)
+               pservice->dev_id = VCODEC_DEVICE_ID_HEVC;
+       else if (strncmp(pservice->name, "vpu_service", 11) == 0)
+               pservice->dev_id = VCODEC_DEVICE_ID_VPU;
+       else if (strncmp(pservice->name, "rkvdec", 6) == 0)
+               pservice->dev_id = VCODEC_DEVICE_ID_RKVDEC;
+       else
+               pservice->dev_id = VCODEC_DEVICE_ID_COMBO;
+
+       if (0 > vpu_get_clk(pservice))
+               goto err;
+
+       vpu_service_power_on(pservice);
+
+       if (of_property_read_bool(np, "reg")) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+               pservice->reg_base = devm_ioremap_resource(pservice->dev, res);
+               if (IS_ERR(pservice->reg_base)) {
+                       vpu_err("ioremap registers base failed\n");
+                       ret = PTR_ERR(pservice->reg_base);
+                       goto err;
+               }
+               pservice->ioaddr = res->start;
+       } else {
+               pservice->reg_base = 0;
+       }
+
+       if (of_property_read_bool(np, "subcnt")) {
+               for (i = 0; i < pservice->subcnt; i++) {
+                       struct device_node *sub_np;
+                       struct platform_device *sub_pdev;
+
+                       sub_np = of_parse_phandle(np, "rockchip,sub", i);
+                       sub_pdev = of_find_device_by_node(sub_np);
+
+                       vcodec_subdev_probe(sub_pdev, pservice);
+               }
+       } else {
+               vcodec_subdev_probe(pdev, pservice);
+       }
+
+       vpu_service_power_off(pservice);
+
+       pr_info("init success\n");
+
+       return 0;
+
+err:
+       pr_info("init failed\n");
+       vpu_service_power_off(pservice);
+       vpu_put_clk(pservice);
+       wake_lock_destroy(&pservice->wake_lock);
+
+       return ret;
+}
+
+static int vcodec_remove(struct platform_device *pdev)
+{
+       struct vpu_subdev_data *data = platform_get_drvdata(pdev);
+
+       vcodec_subdev_remove(data);
+       return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id vcodec_service_dt_ids[] = {
+       {.compatible = "rockchip,vpu_service",},
+       {.compatible = "rockchip,hevc_service",},
+       {.compatible = "rockchip,vpu_combo",},
+       {.compatible = "rockchip,rkvdec",},
+       {},
+};
+#endif
+
+static struct platform_driver vcodec_driver = {
+       .probe = vcodec_probe,
+       .remove = vcodec_remove,
+       .driver = {
+               .name = "vcodec",
+               .owner = THIS_MODULE,
+#if defined(CONFIG_OF)
+               .of_match_table = of_match_ptr(vcodec_service_dt_ids),
+#endif
+       },
+};
+
+static void get_hw_info(struct vpu_subdev_data *data)
+{
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_dec_config *dec = &pservice->dec_config;
+       struct vpu_enc_config *enc = &pservice->enc_config;
+
+       if (cpu_is_rk2928() || cpu_is_rk3036() ||
+           cpu_is_rk30xx() || cpu_is_rk312x() ||
+           cpu_is_rk3188())
+               dec->max_dec_pic_width = 1920;
+       else
+               dec->max_dec_pic_width = 4096;
+
+       if (data->mode == VCODEC_RUNNING_MODE_VPU) {
+               dec->h264_support = 3;
+               dec->jpeg_support = 1;
+               dec->mpeg4_support = 2;
+               dec->vc1_support = 3;
+               dec->mpeg2_support = 1;
+               dec->pp_support = 1;
+               dec->sorenson_support = 1;
+               dec->ref_buf_support = 3;
+               dec->vp6_support = 1;
+               dec->vp7_support = 1;
+               dec->vp8_support = 1;
+               dec->avs_support = 1;
+               dec->jpeg_ext_support = 0;
+               dec->custom_mpeg4_support = 1;
+               dec->reserve = 0;
+               dec->mvc_support = 1;
+
+               if (!cpu_is_rk3036()) {
+                       u32 config_reg = readl_relaxed(data->enc_dev.regs + 63);
+
+                       enc->max_encoded_width = config_reg & ((1 << 11) - 1);
+                       enc->h264_enabled = 1;
+                       enc->mpeg4_enabled = (config_reg >> 26) & 1;
+                       enc->jpeg_enabled = 1;
+                       enc->vs_enabled = (config_reg >> 24) & 1;
+                       enc->rgb_enabled = (config_reg >> 28) & 1;
+                       enc->reg_size = data->reg_size;
+                       enc->reserv[0] = 0;
+                       enc->reserv[1] = 0;
+               }
+
+               pservice->auto_freq = true;
+               vpu_debug(DEBUG_EXTRA_INFO, "vpu_service set to auto frequency mode\n");
+               atomic_set(&pservice->freq_status, VPU_FREQ_BUT);
+
+               pservice->bug_dec_addr = cpu_is_rk30xx();
+       } else if (data->mode == VCODEC_RUNNING_MODE_RKVDEC) {
+               pservice->auto_freq = true;
+               atomic_set(&pservice->freq_status, VPU_FREQ_BUT);
+       } else {
+               /* disable frequency switch in hevc.*/
+               pservice->auto_freq = false;
+       }
+}
+
+static bool check_irq_err(struct vpu_task_info *task, u32 irq_status)
+{
+       vpu_debug(DEBUG_IRQ_CHECK, "task %s status %08x mask %08x\n",
+                 task->name, irq_status, task->error_mask);
+
+       return (task->error_mask & irq_status) ? true : false;
+}
+
+static irqreturn_t vdpu_irq(int irq, void *dev_id)
+{
+       struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_task_info *task = NULL;
+       struct vpu_device *dev = &data->dec_dev;
+       u32 hw_id = data->hw_info->hw_id;
+       u32 raw_status;
+       u32 dec_status;
+
+       task = &data->task_info[TASK_DEC];
+
+       raw_status = readl_relaxed(dev->regs + task->reg_irq);
+       dec_status = raw_status;
+
+       vpu_debug(DEBUG_TASK_INFO, "vdpu_irq reg %d status %x mask: irq %x ready %x error %0x\n",
+                 task->reg_irq, dec_status,
+                 task->irq_mask, task->ready_mask, task->error_mask);
+
+       if (dec_status & task->irq_mask) {
+               time_record(task, 1);
+               vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq dec status %08x\n",
+                         dec_status);
+               if ((dec_status & 0x40001) == 0x40001) {
+                       do {
+                               dec_status =
+                                       readl_relaxed(dev->regs +
+                                               task->reg_irq);
+                       } while ((dec_status & 0x40001) == 0x40001);
+               }
+
+               if (check_irq_err(task, dec_status))
+                       atomic_add(1, &pservice->reset_request);
+
+               writel_relaxed(0, dev->regs + task->reg_irq);
+
+               /*
+                * NOTE: rkvdec need to reset after each task to avoid timeout
+                *       error on H.264 switch to H.265
+                */
+               if (data->mode == VCODEC_RUNNING_MODE_RKVDEC)
+                       writel(0x100000, dev->regs + task->reg_irq);
+
+               /* set clock gating to save power */
+               writel(task->gating_mask, dev->regs + task->reg_irq);
+
+               atomic_add(1, &dev->irq_count_codec);
+               time_diff(task);
+       }
+
+       task = &data->task_info[TASK_PP];
+       if (hw_id != HEVC_ID && hw_id != RKV_DEC_ID) {
+               u32 pp_status = readl_relaxed(dev->regs + task->irq_mask);
+
+               if (pp_status & task->irq_mask) {
+                       time_record(task, 1);
+                       vpu_debug(DEBUG_IRQ_STATUS, "vdpu_irq pp status %08x\n",
+                                 pp_status);
+
+                       if (check_irq_err(task, dec_status))
+                               atomic_add(1, &pservice->reset_request);
+
+                       /* clear pp IRQ */
+                       writel_relaxed(pp_status & (~task->reg_irq),
+                                      dev->regs + task->irq_mask);
+                       atomic_add(1, &dev->irq_count_pp);
+                       time_diff(task);
+               }
+       }
+
+       pservice->irq_status = raw_status;
+
+       if (atomic_read(&dev->irq_count_pp) ||
+           atomic_read(&dev->irq_count_codec))
+               return IRQ_WAKE_THREAD;
+       else
+               return IRQ_NONE;
+}
+
+static irqreturn_t vdpu_isr(int irq, void *dev_id)
+{
+       struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_device *dev = &data->dec_dev;
+
+       mutex_lock(&pservice->lock);
+       if (atomic_read(&dev->irq_count_codec)) {
+               atomic_sub(1, &dev->irq_count_codec);
+               if (pservice->reg_codec == NULL) {
+                       vpu_err("error: dec isr with no task waiting\n");
+               } else {
+                       reg_from_run_to_done(data, pservice->reg_codec);
+                       /* avoid vpu timeout and can't recover problem */
+                       VDPU_SOFT_RESET(data->regs);
+               }
+       }
+
+       if (atomic_read(&dev->irq_count_pp)) {
+               atomic_sub(1, &dev->irq_count_pp);
+               if (pservice->reg_pproc == NULL)
+                       vpu_err("error: pp isr with no task waiting\n");
+               else
+                       reg_from_run_to_done(data, pservice->reg_pproc);
+       }
+       try_set_reg(data);
+       mutex_unlock(&pservice->lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t vepu_irq(int irq, void *dev_id)
+{
+       struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_task_info *task = &data->task_info[TASK_ENC];
+       struct vpu_device *dev = &data->enc_dev;
+       u32 irq_status;
+
+       irq_status = readl_relaxed(dev->regs + task->reg_irq);
+
+       vpu_debug(DEBUG_TASK_INFO, "vepu_irq reg %d status %x mask: irq %x ready %x error %0x\n",
+                 task->reg_irq, irq_status,
+                 task->irq_mask, task->ready_mask, task->error_mask);
+
+       vpu_debug(DEBUG_IRQ_STATUS, "vepu_irq enc status %08x\n", irq_status);
+
+       if (likely(irq_status & task->irq_mask)) {
+               time_record(task, 1);
+
+               if (check_irq_err(task, irq_status))
+                       atomic_add(1, &pservice->reset_request);
+
+               /* clear enc IRQ */
+               writel_relaxed(irq_status & (~task->irq_mask),
+                              dev->regs + task->reg_irq);
+
+               atomic_add(1, &dev->irq_count_codec);
+               time_diff(task);
+       }
+
+       pservice->irq_status = irq_status;
+
+       if (atomic_read(&dev->irq_count_codec))
+               return IRQ_WAKE_THREAD;
+       else
+               return IRQ_NONE;
+}
+
+static irqreturn_t vepu_isr(int irq, void *dev_id)
+{
+       struct vpu_subdev_data *data = (struct vpu_subdev_data *)dev_id;
+       struct vpu_service_info *pservice = data->pservice;
+       struct vpu_device *dev = &data->enc_dev;
+
+       mutex_lock(&pservice->lock);
+       if (atomic_read(&dev->irq_count_codec)) {
+               atomic_sub(1, &dev->irq_count_codec);
+               if (NULL == pservice->reg_codec)
+                       vpu_err("error: enc isr with no task waiting\n");
+               else
+                       reg_from_run_to_done(data, pservice->reg_codec);
+       }
+       try_set_reg(data);
+       mutex_unlock(&pservice->lock);
+       return IRQ_HANDLED;
+}
+
+static int __init vcodec_service_init(void)
+{
+       int ret = platform_driver_register(&vcodec_driver);
+
+       if (ret) {
+               vpu_err("Platform device register failed (%d).\n", ret);
+               return ret;
+       }
+
+#ifdef CONFIG_DEBUG_FS
+       vcodec_debugfs_init();
+#endif
+
+       return ret;
+}
+
+static void __exit vcodec_service_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+       vcodec_debugfs_exit();
+#endif
+
+       platform_driver_unregister(&vcodec_driver);
+}
+
+module_init(vcodec_service_init);
+module_exit(vcodec_service_exit);
+MODULE_LICENSE("Proprietary");
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static int vcodec_debugfs_init(void)
+{
+       parent = debugfs_create_dir("vcodec", NULL);
+       if (!parent)
+               return -1;
+
+       return 0;
+}
+
+static void vcodec_debugfs_exit(void)
+{
+       debugfs_remove(parent);
+}
+
+static struct dentry *vcodec_debugfs_create_device_dir(
+               char *dirname, struct dentry *parent)
+{
+       return debugfs_create_dir(dirname, parent);
+}
+
+static int debug_vcodec_show(struct seq_file *s, void *unused)
+{
+       struct vpu_subdev_data *data = s->private;
+       struct vpu_service_info *pservice = data->pservice;
+       unsigned int i, n;
+       struct vpu_reg *reg, *reg_tmp;
+       struct vpu_session *session, *session_tmp;
+
+       mutex_lock(&pservice->lock);
+       vpu_service_power_on(pservice);
+       if (data->hw_info->hw_id != HEVC_ID) {
+               seq_puts(s, "\nENC Registers:\n");
+               n = data->enc_dev.iosize >> 2;
+
+               for (i = 0; i < n; i++)
+                       seq_printf(s, "\tswreg%d = %08X\n", i,
+                                  readl_relaxed(data->enc_dev.regs + i));
+       }
+
+       seq_puts(s, "\nDEC Registers:\n");
+
+       n = data->dec_dev.iosize >> 2;
+       for (i = 0; i < n; i++)
+               seq_printf(s, "\tswreg%d = %08X\n", i,
+                          readl_relaxed(data->dec_dev.regs + i));
+
+       seq_puts(s, "\nvpu service status:\n");
+
+       list_for_each_entry_safe(session, session_tmp,
+                                &pservice->session, list_session) {
+               seq_printf(s, "session pid %d type %d:\n",
+                          session->pid, session->type);
+
+               list_for_each_entry_safe(reg, reg_tmp,
+                                        &session->waiting, session_link) {
+                       seq_printf(s, "waiting register set %p\n", reg);
+               }
+               list_for_each_entry_safe(reg, reg_tmp,
+                                        &session->running, session_link) {
+                       seq_printf(s, "running register set %p\n", reg);
+               }
+               list_for_each_entry_safe(reg, reg_tmp,
+                                        &session->done, session_link) {
+                       seq_printf(s, "done    register set %p\n", reg);
+               }
+       }
+
+       seq_printf(s, "\npower counter: on %d off %d\n",
+                  atomic_read(&pservice->power_on_cnt),
+                  atomic_read(&pservice->power_off_cnt));
+
+       mutex_unlock(&pservice->lock);
+       vpu_service_power_off(pservice);
+
+       return 0;
+}
+
+static int debug_vcodec_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debug_vcodec_show, inode->i_private);
+}
+
+#endif
+
diff --git a/drivers/video/rockchip/vcodec/vcodec_service.h b/drivers/video/rockchip/vcodec/vcodec_service.h
new file mode 100644 (file)
index 0000000..0b9298c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd
+ * author: chenhengming chm@rock-chips.com
+ *        Alpha Lin, alpha.lin@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H
+#define __ARCH_ARM_MACH_RK29_VCODEC_SERVICE_H
+
+#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */
+
+/*
+ * Ioctl definitions
+ */
+
+/* Use 'k' as magic number */
+#define VPU_IOC_MAGIC                  'l'
+
+#define VPU_IOC_SET_CLIENT_TYPE                _IOW(VPU_IOC_MAGIC, 1, unsigned long)
+#define VPU_IOC_GET_HW_FUSE_STATUS     _IOW(VPU_IOC_MAGIC, 2, unsigned long)
+
+#define VPU_IOC_SET_REG                        _IOW(VPU_IOC_MAGIC, 3, unsigned long)
+#define VPU_IOC_GET_REG                        _IOW(VPU_IOC_MAGIC, 4, unsigned long)
+
+#define VPU_IOC_PROBE_IOMMU_STATUS     _IOR(VPU_IOC_MAGIC, 5, unsigned long)
+
+#ifdef CONFIG_COMPAT
+#define COMPAT_VPU_IOC_SET_CLIENT_TYPE         _IOW(VPU_IOC_MAGIC, 1, u32)
+#define COMPAT_VPU_IOC_GET_HW_FUSE_STATUS      _IOW(VPU_IOC_MAGIC, 2, u32)
+
+#define COMPAT_VPU_IOC_SET_REG                 _IOW(VPU_IOC_MAGIC, 3, u32)
+#define COMPAT_VPU_IOC_GET_REG                 _IOW(VPU_IOC_MAGIC, 4, u32)
+
+#define COMPAT_VPU_IOC_PROBE_IOMMU_STATUS      _IOR(VPU_IOC_MAGIC, 5, u32)
+#endif
+
+enum VPU_CLIENT_TYPE {
+       VPU_ENC                 = 0x0,
+       VPU_DEC                 = 0x1,
+       VPU_PP                  = 0x2,
+       VPU_DEC_PP              = 0x3,
+       VPU_TYPE_BUTT,
+};
+
+/* Hardware decoder configuration description */
+struct vpu_dec_config {
+       /* Maximum video decoding width supported  */
+       u32 max_dec_pic_width;
+       /* Maximum output width of Post-Processor */
+       u32 max_pp_out_pic_width;
+       /* HW supports h.264 */
+       u32 h264_support;
+       /* HW supports JPEG */
+       u32 jpeg_support;
+       /* HW supports MPEG-4 */
+       u32 mpeg4_support;
+       /* HW supports custom MPEG-4 features */
+       u32 custom_mpeg4_support;
+       /* HW supports VC-1 Simple */
+       u32 vc1_support;
+       /* HW supports MPEG-2 */
+       u32 mpeg2_support;
+       /* HW supports post-processor */
+       u32 pp_support;
+       /* HW post-processor functions bitmask */
+       u32 pp_config;
+       /* HW supports Sorenson Spark */
+       u32 sorenson_support;
+       /* HW supports reference picture buffering */
+       u32 ref_buf_support;
+       /* HW supports VP6 */
+       u32 vp6_support;
+       /* HW supports VP7 */
+       u32 vp7_support;
+       /* HW supports VP8 */
+       u32 vp8_support;
+       /* HW supports AVS */
+       u32 avs_support;
+       /* HW supports JPEG extensions */
+       u32 jpeg_ext_support;
+       u32 reserve;
+       /* HW supports H264 MVC extension */
+       u32 mvc_support;
+};
+
+/* Hardware encoder configuration description */
+struct vpu_enc_config {
+       /* Maximum supported width for video encoding (not JPEG) */
+       u32 max_encoded_width;
+       /* HW supports H.264 */
+       u32 h264_enabled;
+       /* HW supports JPEG */
+       u32 jpeg_enabled;
+       /* HW supports MPEG-4 */
+       u32 mpeg4_enabled;
+       /* HW supports video stabilization */
+       u32 vs_enabled;
+       /* HW supports RGB input */
+       u32 rgb_enabled;
+       u32 reg_size;
+       u32 reserv[2];
+};
+
+#endif
+