Merge remote-tracking branch 'kernel-2.6.32/develop' into develop-2.6.36
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rk29 / vpu_service.c
index bf4136f34a3742650bed46d34c6ff1cbd2691c12..b3242e0e9dce026783b02986ad39b52f3e8b4c70 100644 (file)
@@ -1,6 +1,7 @@
 /* arch/arm/mach-rk29/vpu.c
  *
  * Copyright (C) 2010 ROCKCHIP, Inc.
+ * author: chenhengming chm@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
@@ -34,7 +35,8 @@
 #include <linux/mm.h>
 #include <linux/poll.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
 
 #include <asm/uaccess.h>
 
@@ -44,7 +46,6 @@
 #include <mach/pmu.h>
 #include <mach/cru.h>
 
-#define FUN                                    printk("%s\n", __func__)
 
 #define DEC_INTERRUPT_REGISTER                 1
 #define PP_INTERRUPT_REGISTER                  60
@@ -97,6 +98,7 @@ typedef struct vpu_session {
        struct list_head        done;
        wait_queue_head_t       wait;
        pid_t                   pid;
+       atomic_t                task_running;
 } vpu_session;
 
 /**
@@ -121,15 +123,16 @@ typedef struct vpu_device {
 
 typedef struct vpu_service_info {
        spinlock_t              lock;
+       struct timer_list       timer;                  /* timer for power off */
        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                task_running;
+       atomic_t                total_running;
        bool                    enabled;
-       vpu_reg                 *reg_dec;
-       vpu_reg                 *reg_pp;
-       vpu_reg                 *reg_enc;
+       vpu_reg                 *reg_codec;
+       vpu_reg                 *reg_pproc;
+       vpu_reg                 *reg_resev;
        VPUHwDecConfig_t        dec_config;
        VPUHwEncConfig_t        enc_config;
 } vpu_service_info;
@@ -140,6 +143,7 @@ typedef struct vpu_request
        unsigned long   size;
 } vpu_request;
 
+static struct clk *clk_vpu; /* for power on notify */
 static struct clk *aclk_vepu;
 static struct clk *hclk_vepu;
 static struct clk *aclk_ddr_vepu;
@@ -148,12 +152,12 @@ static vpu_service_info service;
 static vpu_device      dec_dev;
 static vpu_device      enc_dev;
 
-static void vpu_service_power_off_work_func(struct work_struct *work);
-static DECLARE_DELAYED_WORK(vpu_service_power_off_work, vpu_service_power_off_work_func);
-#define POWER_OFF_DELAY        3*HZ /* 3s */
+#define POWER_OFF_DELAY        4*HZ /* 4s */
+#define TIMEOUT_DELAY  2*HZ /* 2s */
 
 static void vpu_get_clk(void)
 {
+       clk_vpu         = clk_get(NULL, "vpu");
        aclk_vepu       = clk_get(NULL, "aclk_vepu");
        hclk_vepu       = clk_get(NULL, "hclk_vepu");
        aclk_ddr_vepu   = clk_get(NULL, "aclk_ddr_vepu");
@@ -162,75 +166,151 @@ static void vpu_get_clk(void)
 
 static void vpu_put_clk(void)
 {
+       clk_put(clk_vpu);
        clk_put(aclk_vepu);
        clk_put(hclk_vepu);
        clk_put(aclk_ddr_vepu);
        clk_put(hclk_cpu_vcodec);
 }
 
-static u32 vpu_service_is_working(void)
+static void vpu_reset(void)
 {
-       u32 irq_status;
-       u32 vpu_status = 0;
-       irq_status = readl(dec_dev.hwregs + DEC_INTERRUPT_REGISTER);
-       vpu_status |= irq_status&1;
-       irq_status = readl(enc_dev.hwregs + ENC_INTERRUPT_REGISTER);
-       vpu_status |= irq_status&1;
-       irq_status = readl(dec_dev.hwregs + PP_INTERRUPT_REGISTER);
-       vpu_status |= irq_status&1;
-
-       return vpu_status;
+       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);
+       service.reg_codec = NULL;
+       service.reg_pproc = NULL;
+       service.reg_resev = NULL;
 }
 
-static void vpu_service_power_on(void)
+static void reg_deinit(vpu_reg *reg);
+static void vpu_service_session_clear(vpu_session *session)
 {
-       if (service.enabled)
-               return;
+       vpu_reg *reg, *n;
+       list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
+               reg_deinit(reg);
+       }
+       list_for_each_entry_safe(reg, n, &session->running, session_link) {
+               reg_deinit(reg);
+       }
+       list_for_each_entry_safe(reg, n, &session->done, session_link) {
+               reg_deinit(reg);
+       }
+}
 
-       printk("vpu: power on\n");
-       clk_enable(aclk_vepu);
-       clk_enable(hclk_vepu);
-       clk_enable(hclk_cpu_vcodec);
-       udelay(10);
-       pmu_set_power_domain(PD_VCODEC, true);
-       udelay(10);
-       clk_enable(aclk_ddr_vepu);
-       service.enabled = true;
+static void vpu_service_dump(void)
+{
+       int running;
+       vpu_reg *reg, *reg_tmp;
+       vpu_session *session, *session_tmp;
+
+       running = atomic_read(&service.total_running);
+       printk("total_running %d\n", running);
+
+       printk("reg_codec 0x%.8x\n", (unsigned int)service.reg_codec);
+       printk("reg_pproc 0x%.8x\n", (unsigned int)service.reg_pproc);
+       printk("reg_resev 0x%.8x\n", (unsigned int)service.reg_resev);
+
+       list_for_each_entry_safe(session, session_tmp, &service.session, list_session) {
+               printk("session pid %d type %d:\n", session->pid, session->type);
+               running = atomic_read(&session->task_running);
+               printk("task_running %d\n", running);
+               list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {
+                       printk("waiting register set 0x%.8x\n", (unsigned int)reg);
+               }
+               list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {
+                       printk("running register set 0x%.8x\n", (unsigned int)reg);
+               }
+               list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {
+                       printk("done    register set 0x%.8x\n", (unsigned int)reg);
+               }
+       }
 }
 
 static void vpu_service_power_off(void)
 {
+       int total_running;
+
        if (!service.enabled)
                return;
 
-       while(atomic_read(&service.task_running))
-               udelay(10);
-
-       //while (vpu_service_is_working())
-       //      udelay(10);
+       service.enabled = false;
+       total_running = atomic_read(&service.total_running);
+       if (total_running) {
+               pr_alert("power off when %d task running!!\n", total_running);
+               mdelay(50);
+               pr_alert("delay 50 ms for running task\n");
+               vpu_service_dump();
+       }
 
-       printk("vpu: power off\n");
+       printk("vpu: power off...");
        pmu_set_power_domain(PD_VCODEC, false);
        udelay(10);
        clk_disable(hclk_cpu_vcodec);
        clk_disable(aclk_ddr_vepu);
        clk_disable(hclk_vepu);
        clk_disable(aclk_vepu);
-
-       service.enabled = false;
+       clk_disable(clk_vpu);
+       printk("done\n");
 }
 
-static void vpu_service_power_off_work_func(struct work_struct *work)
+static void vpu_service_power_off_work_func(unsigned long data)
 {
-       pr_debug("work\n");
+       printk("delayed ");
        vpu_service_power_off();
 }
 
+static void vpu_service_power_maintain(void)
+{
+       if (service.enabled) {
+               mod_timer(&service.timer, jiffies + POWER_OFF_DELAY);
+       } else {
+               pr_err("maintain power when power is off!\n");
+       }
+}
+
+static void vpu_service_power_on(void)
+{
+       clk_enable(clk_vpu); /* notify vpu on without lock. */
+
+       spin_lock_bh(&service.lock);
+       if (!service.enabled) {
+               service.enabled = true;
+               printk("vpu: power on\n");
+
+               clk_enable(clk_vpu);
+               clk_enable(aclk_vepu);
+               clk_enable(hclk_vepu);
+               clk_enable(hclk_cpu_vcodec);
+               udelay(10);
+               pmu_set_power_domain(PD_VCODEC, true);
+               udelay(10);
+               clk_enable(aclk_ddr_vepu);
+               init_timer(&service.timer);
+               service.timer.expires = jiffies + POWER_OFF_DELAY;
+               service.timer.function = vpu_service_power_off_work_func;
+               add_timer(&service.timer);
+               spin_unlock_bh(&service.lock);
+       } else {
+               spin_unlock_bh(&service.lock);
+               vpu_service_power_maintain();
+       }
+
+       clk_disable(clk_vpu);
+}
+
 static vpu_reg *reg_init(vpu_session *session, void __user *src, unsigned long size)
 {
        unsigned long flag;
        vpu_reg *reg = kmalloc(sizeof(vpu_reg), GFP_KERNEL);
-       //FUN;
        if (NULL == reg) {
                pr_err("kmalloc fail in reg_init\n");
                return NULL;
@@ -261,36 +341,29 @@ static void reg_deinit(vpu_reg *reg)
        list_del_init(&reg->session_link);
        list_del_init(&reg->status_link);
        kfree(reg);
-       if (reg == service.reg_dec) service.reg_dec = NULL;
-       if (reg == service.reg_enc) service.reg_enc = NULL;
-       if (reg == service.reg_pp)  service.reg_pp  = NULL;
+       if (reg == service.reg_codec) service.reg_codec = NULL;
+       if (reg == service.reg_pproc) service.reg_pproc = NULL;
 }
 
 static void reg_from_wait_to_run(vpu_reg *reg)
 {
-       //FUN;
        list_del_init(&reg->status_link);
        list_add_tail(&reg->status_link, &service.running);
 
        list_del_init(&reg->session_link);
        list_add_tail(&reg->session_link, &reg->session->running);
-
-       atomic_add(1, &service.task_running);
 }
 
 static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count)
 {
        int i;
        u32 *dst = (u32 *)&reg->reg[0];
-       //FUN;
        for (i = 0; i < count; i++)
                *dst++ = *src++;
 }
 
 static void reg_from_run_to_done(vpu_reg *reg)
 {
-       //FUN;
-       //printk("r\n");
        spin_lock(&service.lock);
        list_del_init(&reg->status_link);
        list_add_tail(&reg->status_link, &service.done);
@@ -300,24 +373,26 @@ static void reg_from_run_to_done(vpu_reg *reg)
 
        switch (reg->type) {
        case VPU_ENC : {
-               service.reg_enc = NULL;
+               service.reg_codec = NULL;
                reg_copy_from_hw(reg, enc_dev.hwregs, REG_NUM_ENC);
                break;
        }
        case VPU_DEC : {
-               service.reg_dec = NULL;
+               service.reg_codec = NULL;
                reg_copy_from_hw(reg, dec_dev.hwregs, REG_NUM_DEC);
                break;
        }
        case VPU_PP : {
-               service.reg_pp  = NULL;
+               service.reg_pproc = NULL;
                reg_copy_from_hw(reg, dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_PP);
+               dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
                break;
        }
        case VPU_DEC_PP : {
-               service.reg_dec = NULL;
-               service.reg_pp  = NULL;
+               service.reg_codec = NULL;
+               service.reg_pproc = NULL;
                reg_copy_from_hw(reg, dec_dev.hwregs, REG_NUM_DEC_PP);
+               dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
                break;
        }
        default : {
@@ -325,7 +400,8 @@ static void reg_from_run_to_done(vpu_reg *reg)
                break;
        }
        }
-       atomic_sub(1, &service.task_running);
+       atomic_sub(1, &reg->session->task_running);
+       atomic_sub(1, &service.total_running);
        wake_up_interruptible_sync(&reg->session->wait);
        spin_unlock(&service.lock);
 }
@@ -334,11 +410,12 @@ void reg_copy_to_hw(vpu_reg *reg)
 {
        int i;
        u32 *src = (u32 *)&reg->reg[0];
-
+       atomic_add(1, &service.total_running);
+       atomic_add(1, &reg->session->task_running);
        switch (reg->type) {
        case VPU_ENC : {
                u32 *dst = (u32 *)enc_dev.hwregs;
-               service.reg_enc = reg;
+               service.reg_codec = reg;
 
                dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;
 
@@ -355,11 +432,7 @@ void reg_copy_to_hw(vpu_reg *reg)
        } break;
        case VPU_DEC : {
                u32 *dst = (u32 *)dec_dev.hwregs;
-               if (NULL == service.reg_pp) {
-                       dst[PP_INTERRUPT_REGISTER] = 0;
-               }
-
-               service.reg_dec = reg;
+               service.reg_codec = reg;
 
                for (i = REG_NUM_DEC - 1; i > VPU_REG_DEC_GATE; i--)
                        dst[i] = src[i];
@@ -371,7 +444,7 @@ void reg_copy_to_hw(vpu_reg *reg)
        } break;
        case VPU_PP : {
                u32 *dst = (u32 *)dec_dev.hwregs + PP_INTERRUPT_REGISTER;
-               service.reg_pp = reg;
+               service.reg_pproc = reg;
 
                dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;
 
@@ -384,12 +457,13 @@ void reg_copy_to_hw(vpu_reg *reg)
        } break;
        case VPU_DEC_PP : {
                u32 *dst = (u32 *)dec_dev.hwregs;
-               service.reg_dec = reg;
-               service.reg_pp = reg;
+               service.reg_codec = reg;
+               service.reg_pproc = reg;
 
                for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_DEC_PP; i++)
                        dst[i] = src[i];
 
+               dst[VPU_REG_EN_DEC_PP]   = src[VPU_REG_EN_DEC_PP] | 0x2;
                dsb();
 
                dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;
@@ -398,6 +472,8 @@ void reg_copy_to_hw(vpu_reg *reg)
        } break;
        default : {
                pr_err("unsupport session type %d", reg->type);
+               atomic_sub(1, &service.total_running);
+               atomic_sub(1, &reg->session->task_running);
                break;
        }
        }
@@ -406,32 +482,26 @@ void reg_copy_to_hw(vpu_reg *reg)
 static void try_set_reg(void)
 {
        unsigned long flag;
-       //FUN;
        // first get reg from reg list
        spin_lock_irqsave(&service.lock, flag);
        if (!list_empty(&service.waiting)) {
                vpu_reg *reg = list_entry(service.waiting.next, vpu_reg, status_link);
 
-               if (((VPU_DEC_PP  == reg->type) && (NULL == service.reg_dec) && (NULL == service.reg_pp)) ||
-                       ((VPU_DEC == reg->type) && (NULL == service.reg_dec)) ||
-                       ((VPU_PP  == reg->type) && (NULL == service.reg_pp))  ||
-                       ((VPU_ENC == reg->type) && (NULL == service.reg_enc))) {
+               vpu_service_power_maintain();
+               if (((VPU_DEC_PP == reg->type) && (NULL == service.reg_codec) && (NULL == service.reg_pproc)) ||
+                       ((VPU_DEC == reg->type) && (NULL == service.reg_codec)) ||
+                       ((VPU_PP  == reg->type) && (NULL == service.reg_pproc)) ||
+                       ((VPU_ENC == reg->type) && (NULL == service.reg_codec))) {
                        reg_from_wait_to_run(reg);
-                       __cancel_delayed_work(&vpu_service_power_off_work);
-                       vpu_service_power_on();
                        reg_copy_to_hw(reg);
                }
-               spin_unlock_irqrestore(&service.lock, flag);
-       } else {
-               spin_unlock_irqrestore(&service.lock, flag);
-               schedule_delayed_work(&vpu_service_power_off_work, POWER_OFF_DELAY);
        }
+       spin_unlock_irqrestore(&service.lock, flag);
 }
 
 static int return_reg(vpu_reg *reg, u32 __user *dst)
 {
        int ret = 0;
-       //FUN;
        switch (reg->type) {
        case VPU_ENC : {
                if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_ENC)))
@@ -466,7 +536,6 @@ static int return_reg(vpu_reg *reg, u32 __user *dst)
 static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        vpu_session *session = (vpu_session *)filp->private_data;
-       //FUN;
        if (NULL == session) {
                return -EINVAL;
        }
@@ -509,6 +578,7 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long
                if (NULL == reg) {
                        return -EFAULT;
                } else {
+                       vpu_service_power_on();
                        try_set_reg();
                }
 
@@ -517,26 +587,39 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long
        case VPU_IOC_GET_REG : {
                vpu_request req;
                vpu_reg *reg;
+               unsigned long flag;
                if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {
                        pr_err("VPU_IOC_GET_REG copy_from_user failed\n");
                        return -EFAULT;
                } else {
-                       int ret = wait_event_interruptible_timeout(session->wait, !list_empty(&session->done), HZ);
+                       int ret = wait_event_interruptible_timeout(session->wait, !list_empty(&session->done), TIMEOUT_DELAY);
                        if (unlikely(ret < 0)) {
                                pr_err("pid %d wait task ret %d\n", session->pid, ret);
-                               return ret;
                        } else if (0 == ret) {
-                               pr_err("pid %d wait task done timeout\n", session->pid);
-                               return -ETIMEDOUT;
+                               pr_err("pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));
+                               ret = -ETIMEDOUT;
                        }
-               }
-               {
-                       unsigned long flag;
                        spin_lock_irqsave(&service.lock, flag);
-                       reg = list_entry(session->done.next, vpu_reg, session_link);
-                       return_reg(reg, (u32 __user *)req.req);
+                       if (ret < 0) {
+                               int task_running = atomic_read(&session->task_running);
+                               vpu_service_dump();
+                               if (task_running) {
+                                       atomic_set(&session->task_running, 0);
+                                       atomic_sub(task_running, &service.total_running);
+                                       printk("%d task is running but not return, reset hardware...", task_running);
+                                       vpu_reset();
+                                       printk("done\n");
+                               }
+                               vpu_service_session_clear(session);
+                               spin_unlock_irqrestore(&service.lock, flag);
+                               return ret;
+                       }
                        spin_unlock_irqrestore(&service.lock, flag);
                }
+               spin_lock_irqsave(&service.lock, flag);
+               reg = list_entry(session->done.next, vpu_reg, session_link);
+               return_reg(reg, (u32 __user *)req.req);
+               spin_unlock_irqrestore(&service.lock, flag);
                break;
        }
        default : {
@@ -551,7 +634,6 @@ static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long
 static int vpu_service_check_hw_id(struct vpu_device * dev, const u16 *hwids, size_t num)
 {
        u32 hwid = readl(dev->hwregs);
-       //FUN;
        pr_info("HW ID = 0x%08x\n", hwid);
 
        hwid = (hwid >> 16) & 0xFFFF;   /* product version only */
@@ -569,7 +651,6 @@ static int vpu_service_check_hw_id(struct vpu_device * dev, const u16 *hwids, si
 
 static void vpu_service_release_io(void)
 {
-       //FUN;
        if (dec_dev.hwregs)
                iounmap((void *)dec_dev.hwregs);
        release_mem_region(dec_dev.iobaseaddr, dec_dev.iosize);
@@ -584,7 +665,6 @@ static int vpu_service_reserve_io(void)
        unsigned long iobaseaddr;
        unsigned long iosize;
 
-       //FUN;
        iobaseaddr      = dec_dev.iobaseaddr;
        iosize          = dec_dev.iosize;
 
@@ -634,7 +714,6 @@ err:
 static int vpu_service_open(struct inode *inode, struct file *filp)
 {
        vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL);
-       //FUN;
        if (NULL == session) {
                pr_err("unable to allocate memory for vpu_session.");
                return -ENOMEM;
@@ -649,6 +728,7 @@ static int vpu_service_open(struct inode *inode, struct file *filp)
        init_waitqueue_head(&session->wait);
        /* no need to protect */
        list_add_tail(&session->list_session, &service.session);
+       atomic_set(&session->task_running, 0);
        filp->private_data = (void *)session;
 
        pr_debug("dev opened\n");
@@ -657,35 +737,28 @@ static int vpu_service_open(struct inode *inode, struct file *filp)
 
 static int vpu_service_release(struct inode *inode, struct file *filp)
 {
+       int task_running;
        unsigned long flag;
        vpu_session *session = (vpu_session *)filp->private_data;
-       //FUN;
        if (NULL == session)
                return -EINVAL;
 
+       task_running = atomic_read(&session->task_running);
+       if (task_running) {
+               pr_err("vpu_service session %d still has %d task running when closing\n", session->pid, task_running);
+               msleep(50);
+       }
        wake_up_interruptible_sync(&session->wait);
 
-       msleep(50);
+       spin_lock_irqsave(&service.lock, flag);
        /* remove this filp from the asynchronusly notified filp's */
        //vpu_service_fasync(-1, filp, 0);
        list_del(&session->list_session);
 
-       spin_lock_irqsave(&service.lock, flag);
-       {
-       vpu_reg *reg, *n;
-       list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
-               reg_deinit(reg);
-       }
-       list_for_each_entry_safe(reg, n, &session->running, session_link) {
-               reg_deinit(reg);
-       }
-       list_for_each_entry_safe(reg, n, &session->done, session_link) {
-               reg_deinit(reg);
-       }
-       }
-       spin_unlock_irqrestore(&service.lock, flag);
+       vpu_service_session_clear(session);
 
        kfree(session);
+       spin_unlock_irqrestore(&service.lock, flag);
 
        pr_debug("dev closed\n");
        return 0;
@@ -706,9 +779,8 @@ static struct miscdevice vpu_service_misc_device = {
 
 static void vpu_service_shutdown(struct platform_device *pdev)
 {
-       //FUN;
-       //printk("vpu_service_shutdown\n");
-       __cancel_delayed_work(&vpu_service_power_off_work);
+       pr_cont("shutdown...");
+       del_timer(&service.timer);
        vpu_service_power_off();
        pr_cont("done\n");
 }
@@ -716,11 +788,8 @@ static void vpu_service_shutdown(struct platform_device *pdev)
 static int vpu_service_suspend(struct platform_device *pdev, pm_message_t state)
 {
        bool enabled;
-       //FUN;
-       //printk("vpu_service_suspend\n");
        pr_info("suspend...");
-
-       __cancel_delayed_work(&vpu_service_power_off_work);
+       del_timer(&service.timer);
        enabled = service.enabled;
        vpu_service_power_off();
        service.enabled = enabled;
@@ -729,11 +798,11 @@ static int vpu_service_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int vpu_service_resume(struct platform_device *pdev)
 {
-       //FUN;
-       printk("vpu_service_resume\n");
+       pr_info("resume...");
        if (service.enabled) {
                service.enabled = false;
                vpu_service_power_on();
+               try_set_reg();
        }
        return 0;
 }
@@ -947,10 +1016,10 @@ static irqreturn_t vdpu_isr(int irq, void *dev_id)
                /* clear dec IRQ */
                writel(irq_status_dec & (~DEC_INTERRUPT_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER);
                pr_debug("DEC IRQ received!\n");
-               if (NULL == service.reg_dec) {
+               if (NULL == service.reg_codec) {
                        pr_err("dec isr with no task waiting\n");
                } else {
-                       reg_from_run_to_done(service.reg_dec);
+                       reg_from_run_to_done(service.reg_codec);
                }
        }
 
@@ -958,11 +1027,10 @@ static irqreturn_t vdpu_isr(int irq, void *dev_id)
                /* clear pp IRQ */
                writel(irq_status_pp & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
                pr_debug("PP IRQ received!\n");
-
-               if (NULL == service.reg_pp) {
+               if (NULL == service.reg_pproc) {
                        pr_err("pp isr with no task waiting\n");
                } else {
-                       reg_from_run_to_done(service.reg_pp);
+                       reg_from_run_to_done(service.reg_pproc);
                }
        }
        try_set_reg();
@@ -980,11 +1048,10 @@ static irqreturn_t vepu_isr(int irq, void *dev_id)
                /* clear enc IRQ */
                writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);
                pr_debug("ENC IRQ received!\n");
-
-               if (NULL == service.reg_enc) {
+               if (NULL == service.reg_codec) {
                        pr_err("enc isr with no task waiting\n");
                } else {
-                       reg_from_run_to_done(service.reg_enc);
+                       reg_from_run_to_done(service.reg_codec);
                }
        }
        try_set_reg();
@@ -1007,11 +1074,10 @@ static int __init vpu_service_init(void)
        INIT_LIST_HEAD(&service.done);
        INIT_LIST_HEAD(&service.session);
        spin_lock_init(&service.lock);
-       service.reg_dec         = NULL;
-       service.reg_enc         = NULL;
-       service.reg_pp          = NULL;
-       atomic_set(&service.task_running, 0);
-       service.enabled = false;
+       service.reg_codec       = NULL;
+       service.reg_pproc       = NULL;
+       atomic_set(&service.total_running, 0);
+       service.enabled         = false;
 
        vpu_get_clk();
        vpu_service_power_on();
@@ -1044,6 +1110,7 @@ static int __init vpu_service_init(void)
        platform_device_register(&vpu_service_device);
        platform_driver_probe(&vpu_service_driver, NULL);
        get_hw_info();
+       del_timer(&service.timer);
        vpu_service_power_off();
        pr_info("init success\n");
 
@@ -1056,6 +1123,7 @@ err_req_vepu_irq:
 err_req_vdpu_irq:
        pr_info("init failed\n");
 err_reserve_io:
+       del_timer(&service.timer);
        vpu_service_power_off();
        vpu_service_release_io();
        vpu_put_clk();
@@ -1065,7 +1133,7 @@ err_reserve_io:
 
 static void __exit vpu_service_exit(void)
 {
-       __cancel_delayed_work(&vpu_service_power_off_work);
+       del_timer(&service.timer);
        vpu_service_power_off();
        platform_device_unregister(&vpu_service_device);
        platform_driver_unregister(&vpu_service_driver);
@@ -1090,7 +1158,6 @@ static int proc_vpu_service_show(struct seq_file *s, void *v)
        vpu_reg *reg, *reg_tmp;
        vpu_session *session, *session_tmp;
 
-       cancel_delayed_work_sync(&vpu_service_power_off_work);
        vpu_service_power_on();
        seq_printf(s, "\nENC Registers:\n");
        n = enc_dev.iosize >> 2;
@@ -1119,7 +1186,6 @@ static int proc_vpu_service_show(struct seq_file *s, void *v)
                }
        }
        spin_unlock_irqrestore(&service.lock, flag);
-       schedule_delayed_work(&vpu_service_power_off_work, POWER_OFF_DELAY);
 
        return 0;
 }