rk29: vpu: manager clock
author黄涛 <huangtao@rock-chips.com>
Fri, 24 Dec 2010 01:09:36 +0000 (09:09 +0800)
committer黄涛 <huangtao@rock-chips.com>
Fri, 24 Dec 2010 01:09:48 +0000 (09:09 +0800)
arch/arm/mach-rk29/Kconfig
arch/arm/mach-rk29/clock.c
arch/arm/mach-rk29/include/mach/vpu.h
arch/arm/mach-rk29/vpu.c

index e7bc0ff9ee01c16ec453b58d3cce3b0fdf77c9ce..ded023c1fc7a8c059644af573d6f4db347ad1520 100644 (file)
@@ -43,14 +43,6 @@ config RK29_VPU_DEBUG
           This is an option for the developers; most people should
           say N here.  This enables RK29 VPU driver debugging.
 
-config RK29_VPU_HW_PERFORMANCE
-       bool "RK29 VPU HW_PERFORMANCE ioctl support"
-        depends on RK29_VPU != n
-       default n
-        help
-          This is an option for the developers; most people should
-          say N here.  This enables RK29 VPU driver HW_PERFORMANCE ioctl.
-
 endmenu
 
 endif
index 1e3a30b0672f2df8d21ec53b15f67d1e31027771..cdf713a6562b284bf93b99e8cf2c0349cf10d3f0 100755 (executable)
@@ -2324,14 +2324,6 @@ static void __init clk_enable_init_clocks(void)
 #ifdef CONFIG_DEBUG_LL
        clk_enable_nolock(&clk_uart1);
 #endif
-       /* vpu */
-       clk_enable_nolock(&aclk_vdpu);
-       clk_enable_nolock(&hclk_vdpu);
-       clk_enable_nolock(&clk_aclk_ddr_vdpu);
-       clk_enable_nolock(&aclk_vepu);
-       clk_enable_nolock(&hclk_vepu);
-       clk_enable_nolock(&clk_aclk_ddr_vepu);
-       clk_enable_nolock(&clk_hclk_cpu_vcodec);
 }
 
 static int __init clk_disable_unused(void)
@@ -2349,7 +2341,7 @@ static int __init clk_disable_unused(void)
        }
        mutex_unlock(&clocks_mutex);
 
-//     pmu_set_power_domain(PD_VCODEC, false);
+       pmu_set_power_domain(PD_VCODEC, false);
 //     pmu_set_power_domain(PD_DISPLAY, false);
 //     pmu_set_power_domain(PD_GPU, false);
 
index d376f27a3ae9eee4a4834d519eef6cbcef5b5dc9..6748633afdda314594179bb82c8843edef69cb2b 100644 (file)
 /* Use 'k' as magic number */
 #define VPU_IOC_MAGIC  'k'
 
-#define VPU_IOC_PP_INSTANCE     _IO(VPU_IOC_MAGIC, 1)   /* the client is pp instance */
-#define VPU_IOC_HW_PERFORMANCE  _IO(VPU_IOC_MAGIC, 2)   /* get monotonic time (struct timespec) for HW performance */
-
-#define VPU_IOC_GHWOFFSET       _IOR(VPU_IOC_MAGIC, 3, unsigned long *)
-#define VPU_IOC_GHWIOSIZE       _IOR(VPU_IOC_MAGIC, 4, unsigned int *)
-
-#define VPU_IOC_CLI             _IO(VPU_IOC_MAGIC, 5)
-#define VPU_IOC_STI             _IO(VPU_IOC_MAGIC, 6)
-
-#define VPU_IOC_DEC_INSTANCE    _IO(VPU_IOC_MAGIC, 7)
-#define VPU_IOC_ENC_INSTANCE    _IO(VPU_IOC_MAGIC, 8)
-
-#define VPU_IOC_MAXNR           8
+#define VPU_IOC_POWER_ON       _IO(VPU_IOC_MAGIC, 1)
+#define VPU_IOC_POWER_OFF      _IO(VPU_IOC_MAGIC, 2)
 
 #endif
index 7bab707e9abdc7dbd30220bc8fb4a6ed56fd3f68..35ccca7a3e0230e3694f9128e883759eb51484b3 100644 (file)
@@ -20,6 +20,8 @@
 #define pr_fmt(fmt) "VPU: " fmt
 #endif
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/poll.h>
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-#include <linux/time.h>
-#endif
 
 #include <asm/uaccess.h>
 
 #include <mach/irqs.h>
 #include <mach/vpu.h>
 #include <mach/rk29_iomap.h>
+#include <mach/pmu.h>
 
 #define DEC_INTERRUPT_REGISTER     1
 #define PP_INTERRUPT_REGISTER      60
@@ -66,87 +66,86 @@ static struct vpu_device pp_dev;
 static struct vpu_device enc_dev;
 
 struct vpu_client {
-       struct vpu_device       *dev;
        atomic_t                dec_event;
        atomic_t                enc_event;
        struct fasync_struct    *async_queue;
        wait_queue_head_t       wait;
        struct file             *filp;  /* for /proc/vpu */
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-       struct timespec         end_time;
-#endif
+       bool                    enabled;
 };
 static struct vpu_client client;
 
+static struct clk *aclk_vepu;
+static struct clk *hclk_vepu;
+static struct clk *aclk_ddr_vepu;
+static struct clk *hclk_cpu_vcodec;
+
 static void vpu_release_io(void);
 
-static long vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static void vpu_get_clk(void)
 {
-       int err = 0;
-       struct vpu_device *dev = client.dev;
+       aclk_vepu = clk_get(NULL, "aclk_vepu");
+       hclk_vepu = clk_get(NULL, "hclk_vepu");
+       aclk_ddr_vepu = clk_get(NULL, "aclk_ddr_vepu");
+       hclk_cpu_vcodec = clk_get(NULL, "hclk_cpu_vcodec");
+}
 
-       pr_debug("ioctl cmd 0x%08x\n", cmd);
+static void vpu_put_clk(void)
+{
+       clk_put(aclk_vepu);
+       clk_put(hclk_vepu);
+       clk_put(aclk_ddr_vepu);
+       clk_put(hclk_cpu_vcodec);
+}
 
-       if (!dev)
-               return -EINVAL;
+static void vpu_power_on(void)
+{
+       pr_debug("power on\n");
+       if (client.enabled)
+               return;
+       pr_debug("power domain on\n");
+       pmu_set_power_domain(PD_VCODEC, true);
+       udelay(10);     // max 5358 ns
+       while (!pmu_power_domain_is_on(PD_VCODEC)) {
+               pr_debug("waiting for on\n");
+               msleep(1);
+       }
+       clk_enable(aclk_vepu);
+       clk_enable(hclk_vepu);
+       clk_enable(aclk_ddr_vepu);
+       clk_enable(hclk_cpu_vcodec);
+       client.enabled = true;
+}
 
-       /*
-        * extract the type and number bitfields, and don't decode
-        * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
-        */
-       if (_IOC_TYPE(cmd) != VPU_IOC_MAGIC)
-               return -ENOTTY;
-       if (_IOC_NR(cmd) > VPU_IOC_MAXNR)
-               return -ENOTTY;
+static void vpu_power_off(void)
+{
+       pr_debug("power off\n");
+       if (!client.enabled)
+               return;
+       clk_disable(hclk_cpu_vcodec);
+       clk_disable(aclk_ddr_vepu);
+       clk_disable(hclk_vepu);
+       clk_disable(aclk_vepu);
+       pr_debug("power domain off\n");
+       pmu_set_power_domain(PD_VCODEC, false);
+       client.enabled = false;
+}
 
-       /*
-        * the direction is a bitmask, and VERIFY_WRITE catches R/W
-        * transfers. `Type' is user-oriented, while
-        * access_ok is kernel-oriented, so the concept of "read" and
-        * "write" is reversed
-        */
-       if (_IOC_DIR(cmd) & _IOC_READ)
-               err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
-       else if (_IOC_DIR(cmd) & _IOC_WRITE)
-               err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
-       if (err)
-               return -EFAULT;
+static long vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       pr_debug("ioctl cmd 0x%08x\n", cmd);
 
        switch (cmd) {
-       case VPU_IOC_CLI:
-               disable_irq(dev->irq);
-               break;
-
-       case VPU_IOC_STI:
-               enable_irq(dev->irq);
-               break;
-
-       case VPU_IOC_GHWOFFSET:
-               put_user(dev->iobaseaddr, (unsigned long *)arg);
-               break;
-
-       case VPU_IOC_GHWIOSIZE:
-               put_user(dev->iosize, (unsigned int *)arg);
-               break;
-
-       case VPU_IOC_DEC_INSTANCE:
-               client.dev = &dec_dev;
-               break;
-
-       case VPU_IOC_PP_INSTANCE:
-               client.dev = &pp_dev;
-               break;
-
-       case VPU_IOC_ENC_INSTANCE:
-               client.dev = &enc_dev;
+       case VPU_IOC_POWER_ON: {
+               vpu_power_on();
                break;
-
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-       case VPU_IOC_HW_PERFORMANCE:
-               put_user(client.end_time.tv_sec, (long *)arg);
-               put_user(client.end_time.tv_nsec, (long *)arg + 1);
+       }
+       case VPU_IOC_POWER_OFF: {
+               vpu_power_off();
                break;
-#endif
+       }
+       default:
+               return -ENOTTY;
        }
 
        return 0;
@@ -156,8 +155,10 @@ static int vpu_open(struct inode *inode, struct file *filp)
 {
        if (client.filp)
                return -EBUSY;
-       client.dev = &dec_dev;
+
        client.filp = filp;
+       vpu_power_on();
+
        pr_debug("dev opened\n");
        return nonseekable_open(inode, filp);
 }
@@ -175,6 +176,8 @@ static int vpu_release(struct inode *inode, struct file *filp)
        client.async_queue = NULL;
        client.filp = NULL;
 
+       vpu_power_off();
+
        pr_debug("dev closed\n");
        return 0;
 }
@@ -271,9 +274,6 @@ static irqreturn_t hx170dec_isr(int irq, void *dev_id)
        irq_status_pp = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
 
        if (irq_status_dec & DEC_INTERRUPT_BIT) {
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-               ktime_get_ts(&client.end_time);
-#endif
                /* clear dec IRQ */
                writel(irq_status_dec & (~DEC_INTERRUPT_BIT),
                                dev->hwregs + DEC_INTERRUPT_REGISTER);
@@ -284,9 +284,6 @@ static irqreturn_t hx170dec_isr(int irq, void *dev_id)
        }
 
        if (irq_status_pp & PP_INTERRUPT_BIT) {
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-               ktime_get_ts(&client.end_time);
-#endif
                /* clear pp IRQ */
                writel(irq_status_pp & (~DEC_INTERRUPT_BIT),
                                dev->hwregs + PP_INTERRUPT_REGISTER);
@@ -311,9 +308,6 @@ static irqreturn_t hx280enc_isr(int irq, void *dev_id)
        irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER);
 
        if (likely(irq_status & ENC_INTERRUPT_BIT)) {
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-               ktime_get_ts(&client.end_time);
-#endif
                /* clear enc IRQ */
                writel(irq_status & (~ENC_INTERRUPT_BIT),
                                dev->hwregs + ENC_INTERRUPT_REGISTER);
@@ -450,6 +444,9 @@ static int __init vpu_init(void)
        enc_dev.iosize = ENC_IO_SIZE;
        enc_dev.irq = IRQ_VEPU;
 
+       vpu_get_clk();
+       vpu_power_on();
+
        ret = vpu_reserve_io();
        if (ret < 0) {
                goto err_reserve_io;
@@ -482,6 +479,7 @@ static int __init vpu_init(void)
                goto err_register;
        }
 
+       vpu_power_off();
        pr_info("init success\n");
 
        return 0;
@@ -493,12 +491,16 @@ err_req_vepu_irq:
 err_req_vdpu_irq:
        vpu_release_io();
 err_reserve_io:
+       vpu_power_off();
+       vpu_put_clk();
        pr_info("init failed\n");
        return ret;
 }
 
 static void __exit vpu_exit(void)
 {
+       vpu_power_on();
+
        /* clear dec IRQ */
        writel(0, dec_dev.hwregs + DEC_INTERRUPT_REGISTER);
        /* clear pp IRQ */
@@ -512,6 +514,9 @@ static void __exit vpu_exit(void)
        free_irq(IRQ_VEPU, (void *)&enc_dev);
        free_irq(IRQ_VDPU, (void *)&dec_dev);
        vpu_release_io();
+
+       vpu_power_off();
+       vpu_put_clk();
 }
 
 module_init(vpu_init);
@@ -527,23 +532,15 @@ static int proc_vpu_show(struct seq_file *s, void *v)
        unsigned int i, n;
        s32 irq_event = atomic_read(&client.dec_event) | atomic_read(&client.enc_event);
 
-       if (client.filp) {
-               seq_printf(s, "Opened\n");
-               seq_printf(s, "%s instance\n", client.dev == &dec_dev ? "DEC" : client.dev == &pp_dev ? "PP" : "ENC");
-       } else {
-               seq_printf(s, "Closed\n");
-       }
-
+       seq_printf(s, client.filp ? "Opened\n" : "Closed\n");
        seq_printf(s, "irq_event: 0x%08x (%s%s%s%s%s)\n", irq_event,
                   irq_event & VPU_IRQ_EVENT_DEC_BIT ? "DEC " : "",
                   irq_event & VPU_IRQ_EVENT_DEC_IRQ_BIT ? "DEC_IRQ " : "",
                   irq_event & VPU_IRQ_EVENT_PP_IRQ_BIT ? "PP_IRQ " : "",
                   irq_event & VPU_IRQ_EVENT_ENC_BIT ? "ENC " : "",
                   irq_event & VPU_IRQ_EVENT_ENC_IRQ_BIT ? "ENC_IRQ" : "");
-#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE
-       seq_printf(s, "end_time: %ld.%09ld\n", client.end_time.tv_sec, client.end_time.tv_nsec);
-#endif
 
+       vpu_power_on();
        seq_printf(s, "\nENC Registers:\n");
        n = enc_dev.iosize >> 2;
        for (i = 0; i < n; i++) {
@@ -554,6 +551,7 @@ static int proc_vpu_show(struct seq_file *s, void *v)
        for (i = 0; i < n; i++) {
                seq_printf(s, "\tswreg%d = %08X\n", i, readl(dec_dev.hwregs + i));
        }
+       vpu_power_off();
        return 0;
 }