rk29: vpu use kernel register config
author陈恒明 <chm@rockchip.com>
Thu, 3 Mar 2011 06:41:38 +0000 (14:41 +0800)
committer陈恒明 <chm@rockchip.com>
Thu, 3 Mar 2011 06:41:38 +0000 (14:41 +0800)
arch/arm/mach-rk29/include/mach/vpu.h
arch/arm/mach-rk29/vpu.c

index 6748633afdda314594179bb82c8843edef69cb2b..3198ab31f9b77c131ef545d2211fe5fef9f81693 100644 (file)
  * Ioctl definitions
  */
 
+#define VPU_aclk_vepu           0
+#define VPU_hclk_vepu           1
+#define VPU_aclk_ddr_vepu       2
+#define VPU_hclk_cpu_vcodec     3
+
 /* Use 'k' as magic number */
 #define VPU_IOC_MAGIC  'k'
 
-#define VPU_IOC_POWER_ON       _IO(VPU_IOC_MAGIC, 1)
-#define VPU_IOC_POWER_OFF      _IO(VPU_IOC_MAGIC, 2)
+#define VPU_IOC_CLOCK_ON        _IOW(VPU_IOC_MAGIC, 1, unsigned long)
+#define VPU_IOC_CLOCK_OFF       _IOW(VPU_IOC_MAGIC, 2, unsigned long)
+
+#define VPU_IOC_CLOCK_RESET     _IOW(VPU_IOC_MAGIC, 3, unsigned long)
+#define VPU_IOC_CLOCK_UNRESET   _IOW(VPU_IOC_MAGIC, 4, unsigned long)
+
+#define VPU_IOC_DOMAIN_ON       _IO(VPU_IOC_MAGIC, 5)
+#define VPU_IOC_DOMAIN_OFF      _IO(VPU_IOC_MAGIC, 6)
+
+#define VPU_IOC_WR_DEC          _IOW(VPU_IOC_MAGIC, 8,  unsigned long)
+#define VPU_IOC_WR_DEC_PP       _IOW(VPU_IOC_MAGIC, 9,  unsigned long)
+#define VPU_IOC_WR_ENC          _IOW(VPU_IOC_MAGIC, 10, unsigned long)
+#define VPU_IOC_WR_PP           _IOW(VPU_IOC_MAGIC, 11, unsigned long)
+
+#define VPU_IOC_RD_DEC          _IOW(VPU_IOC_MAGIC, 12, unsigned long)
+#define VPU_IOC_RD_DEC_PP       _IOW(VPU_IOC_MAGIC, 13, unsigned long)
+#define VPU_IOC_RD_ENC          _IOW(VPU_IOC_MAGIC, 14, unsigned long)
+#define VPU_IOC_RD_PP           _IOW(VPU_IOC_MAGIC, 15, unsigned long)
+
+#define VPU_IOC_CLS_IRQ         _IOW(VPU_IOC_MAGIC, 16, unsigned long)
 
 #endif
index 16dfd60a929308677d3a2580805e86964fe78ffc..4f8913bfc3e599a54b97d19c015fb5a47c6111c0 100644 (file)
 #include <mach/cru.h>
 
 
-#define DEC_INTERRUPT_REGISTER     1
-#define PP_INTERRUPT_REGISTER      60
-#define ENC_INTERRUPT_REGISTER     1
+#define DEC_INTERRUPT_REGISTER    1
+#define PP_INTERRUPT_REGISTER     60
+#define ENC_INTERRUPT_REGISTER    1
 
-#define DEC_INTERRUPT_BIT            0x100
-#define PP_INTERRUPT_BIT             0x100
-#define ENC_INTERRUPT_BIT            0x1
+#define DEC_INTERRUPT_BIT                       0x100
+#define PP_INTERRUPT_BIT                        0x100
+#define ENC_INTERRUPT_BIT                       0x1
 
-#define DEC_IO_SIZE                 ((100 + 1) * 4)    /* bytes */
-#define ENC_IO_SIZE                 (96 * 4)   /* bytes */
+#define DEC_IO_SIZE                            ((100 + 1) * 4) /* bytes */
+#define ENC_IO_SIZE                            (96 * 4)        /* bytes */
+
+typedef enum
+{
+       VPU_ENC                                 = 0x0,
+       VPU_DEC                                 = 0x1,
+       VPU_PP                                  = 0x2,
+       VPU_DEC_PP                              = 0x3,
+       VPU_TYPE_BUTT                   ,
+} VPU_CLIENT_TYPE;
+
+#define REG_NUM_DEC                            (60)
+#define REG_NUM_PP                                     (41)
+#define REG_NUM_ENC                            (96)
+#define REG_NUM_DEC_PP                         (REG_NUM_DEC+REG_NUM_PP)
+#define SIZE_REG(reg)                          ((reg)*4)
 
 static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 };
 static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 };
+static u32     regs_enc[REG_NUM_ENC];
+static u32     regs_dec[REG_NUM_DEC_PP];
+static u32 *regs_pp = &regs_dec[REG_NUM_DEC];
+
+#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)
 
 struct vpu_device {
        unsigned long   iobaseaddr;
@@ -73,7 +105,7 @@ struct vpu_client {
        atomic_t                enc_event;
        struct fasync_struct    *async_queue;
        wait_queue_head_t       wait;
-       struct file             *filp;  /* for /proc/vpu */
+       struct file     *filp;  /* for /proc/vpu */
        bool                    enabled;
 };
 static struct vpu_client client;
@@ -146,19 +178,343 @@ static void vpu_power_off(void)
        client.enabled = false;
 }
 
+static void vpu_clock_on(unsigned long id)
+{
+       switch (id) {
+       case VPU_aclk_vepu :
+               printk("vpu_clock_on: aclk_vepu in\n");
+               clk_enable(aclk_vepu);
+               printk("vpu_clock_on: aclk_vepu out\n");
+               break;
+       case VPU_hclk_vepu :
+               printk("vpu_clock_on: hclk_vepu in\n");
+               clk_enable(hclk_vepu);
+               printk("vpu_clock_on: hclk_vepu out\n");
+               break;
+       case VPU_aclk_ddr_vepu :
+               printk("vpu_clock_on: aclk_ddr_vepu in\n");
+               clk_enable(aclk_ddr_vepu);
+               printk("vpu_clock_on: aclk_ddr_vepu out\n");
+               break;
+       case VPU_hclk_cpu_vcodec :
+               printk("vpu_clock_on: hclk_cpu_vcodec in\n");
+               clk_enable(hclk_cpu_vcodec);
+               printk("vpu_clock_on: hclk_cpu_vcodec out\n");
+               break;
+       default :
+               printk("vpu_clock_on: invalid id %lu\n", id);
+               break;
+       }
+
+       return ;
+}
+
+static void vpu_clock_off(unsigned long id)
+{
+       switch (id) {
+       case VPU_aclk_vepu :
+               printk("vpu_clock_off: aclk_vepu in\n");
+               clk_disable(aclk_vepu);
+               printk("vpu_clock_off: aclk_vepu out\n");
+               break;
+       case VPU_hclk_vepu :
+               printk("vpu_clock_off: hclk_vepu in\n");
+               clk_disable(hclk_vepu);
+               printk("vpu_clock_off: hclk_vepu out\n");
+               break;
+       case VPU_aclk_ddr_vepu :
+               printk("vpu_clock_off: aclk_ddr_vepu in\n");
+               clk_disable(aclk_ddr_vepu);
+               printk("vpu_clock_off: aclk_ddr_vepu out\n");
+               break;
+       case VPU_hclk_cpu_vcodec :
+               printk("vpu_clock_off: hclk_cpu_vcodec in\n");
+               clk_disable(hclk_cpu_vcodec);
+               printk("vpu_clock_off: hclk_cpu_vcodec out\n");
+               break;
+       default :
+               printk("vpu_clock_off: invalid id %lu\n", id);
+               break;
+       }
+
+       return ;
+}
+
+static void vpu_clock_reset(unsigned long id)
+{
+       if (id == SOFT_RST_CPU_VODEC_A2A_AHB ||
+               id == SOFT_RST_VCODEC_AHB_BUS ||
+               id == SOFT_RST_VCODEC_AXI_BUS ||
+               id == SOFT_RST_DDR_VCODEC_PORT) {
+               printk("vpu_clock_reset: id %lu in\n", id);
+               cru_set_soft_reset(id, true);
+               printk("vpu_clock_reset: id %lu out\n", id);
+       } else {
+               printk("vpu_clock_reset: invalid id %lu\n", id);
+       }
+
+       return ;
+}
+
+static void vpu_clock_unreset(unsigned long id)
+{
+       if (id == SOFT_RST_CPU_VODEC_A2A_AHB ||
+               id == SOFT_RST_VCODEC_AHB_BUS ||
+               id == SOFT_RST_VCODEC_AXI_BUS ||
+               id == SOFT_RST_DDR_VCODEC_PORT) {
+               printk("vpu_clock_unreset: id %lu in\n", id);
+               cru_set_soft_reset(id, true);
+               printk("vpu_clock_unreset: id %lu out\n", id);
+       } else {
+               printk("vpu_clock_unreset: invalid id %lu\n", id);
+       }
+
+       return ;
+}
+
+static void vpu_domain_on(void)
+{
+       printk("vpu_domain_on in\n");
+       pmu_set_power_domain(PD_VCODEC, true);
+       printk("vpu_domain_on out\n");
+}
+
+static void vpu_domain_off(void)
+{
+       printk("vpu_domain_off in\n");
+       pmu_set_power_domain(PD_VCODEC, false);
+       printk("vpu_domain_off out\n");
+}
+
+static long vpu_write_dec(u32 *src)
+{
+       int i;
+       u32 *dst = (u32 *)dec_dev.hwregs;
+
+       dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;
+
+       for (i = VPU_REG_DEC_GATE + 1; i < REG_NUM_DEC; i++)
+               dst[i] = src[i];
+
+       dst[VPU_REG_EN_DEC]   = src[VPU_REG_EN_DEC];
+
+       return 0;
+}
+
+static long vpu_write_dec_pp(u32 *src)
+{
+       int i;
+       u32 *dst = (u32 *)dec_dev.hwregs;
+
+       for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_DEC_PP; i++)
+               dst[i] = src[i];
+
+       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];
+
+       return 0;
+}
+
+static long vpu_write_enc(u32 *src)
+{
+       int i;
+       u32 *dst = (u32 *)enc_dev.hwregs;
+
+       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 < REG_NUM_ENC; i++)
+               dst[i] = src[i];
+
+       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];
+
+       return 0;
+}
+
+static long vpu_write_pp(u32 *src)
+{
+       int i;
+       u32 *dst = (u32 *)dec_dev.hwregs + PP_INTERRUPT_REGISTER;
+
+       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_PP; i++)
+               dst[i] = src[i];
+
+       dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];
+
+       return 0;
+}
+
+static long vpu_read_dec(u32 *dst)
+{
+       int i;
+       volatile u32 *src = dec_dev.hwregs;
+
+       for (i = 0; i < REG_NUM_DEC; i++)
+               *dst++ = *src++;
+
+       return 0;
+}
+
+static long vpu_read_dec_pp(u32 *dst)
+{
+       int i;
+       volatile u32 *src = dec_dev.hwregs;
+
+       for (i = 0; i < REG_NUM_DEC_PP; i++)
+               *dst++ = *src++;
+
+       return 0;
+}
+
+static long vpu_read_enc(u32 *dst)
+{
+       int i;
+       volatile u32 *src = enc_dev.hwregs;
+
+       for (i = 0; i < REG_NUM_ENC; i++)
+               *dst++ = *src++;
+
+       return 0;
+}
+
+static long vpu_read_pp(u32 *dst)
+{
+       int i;
+       volatile u32 *src = dec_dev.hwregs + PP_INTERRUPT_REGISTER;
+
+       for (i = 0; i < REG_NUM_PP; i++)
+               *dst++ = *src++;
+
+       return 0;
+}
+
+static long vpu_clear_irqs(VPU_CLIENT_TYPE type)
+{
+       long ret = 0;
+       switch (type) {
+       case VPU_ENC : {
+               writel(0, &enc_dev.hwregs[ENC_INTERRUPT_REGISTER]);
+               break;
+       }
+       case VPU_DEC :
+       case VPU_DEC_PP : {
+               writel(0, &dec_dev.hwregs[DEC_INTERRUPT_REGISTER]);
+               break;
+       }
+       case VPU_PP : {
+               writel(0, &pp_dev.hwregs[PP_INTERRUPT_REGISTER]);
+               break;
+       }
+       default : {
+               ret = -1;
+       }
+       }
+
+       return ret;
+}
+
 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_POWER_ON: {
+       case VPU_IOC_CLOCK_ON: {
+               //vpu_clock_on(arg);
                vpu_power_on();
                break;
        }
-       case VPU_IOC_POWER_OFF: {
+       case VPU_IOC_CLOCK_OFF: {
+               //vpu_clock_off(arg);
                vpu_power_off();
                break;
        }
+       case VPU_IOC_CLOCK_RESET: {
+               vpu_clock_reset(arg);
+               break;
+       }
+       case VPU_IOC_CLOCK_UNRESET: {
+               vpu_clock_unreset(arg);
+               break;
+       }
+       case VPU_IOC_DOMAIN_ON: {
+               vpu_domain_on();
+               break;
+       }
+       case VPU_IOC_DOMAIN_OFF: {
+               vpu_domain_off();
+               break;
+       }
+
+
+       case VPU_IOC_WR_DEC: {
+               if (copy_from_user(regs_dec, (void __user *)arg, SIZE_REG(REG_NUM_DEC)))
+                       return -EFAULT;
+               vpu_write_dec(regs_dec);
+               break;
+       }
+
+       case VPU_IOC_WR_DEC_PP: {
+               if (copy_from_user(regs_dec, (void __user *)arg, SIZE_REG(REG_NUM_DEC_PP)))
+                       return -EFAULT;
+               vpu_write_dec_pp(regs_dec);
+               break;
+       }
+
+       case VPU_IOC_WR_ENC: {
+               if (copy_from_user(regs_enc, (void __user *)arg, SIZE_REG(REG_NUM_ENC)))
+                       return -EFAULT;
+               vpu_write_enc(regs_enc);
+               break;
+       }
+
+       case VPU_IOC_WR_PP: {
+               if (copy_from_user(regs_pp, (void __user *)arg, SIZE_REG(REG_NUM_PP)))
+                       return -EFAULT;
+               vpu_write_pp(regs_pp);
+               break;
+       }
+
+
+       case VPU_IOC_RD_DEC: {
+               vpu_read_dec(regs_dec);
+               if (copy_to_user((void __user *)arg, regs_dec, SIZE_REG(REG_NUM_DEC)))
+                       return -EFAULT;
+               break;
+       }
+
+       case VPU_IOC_RD_DEC_PP: {
+               vpu_read_dec_pp(regs_dec);
+               if (copy_to_user((void __user *)arg, regs_dec, SIZE_REG(REG_NUM_DEC_PP)))
+                       return -EFAULT;
+               break;
+       }
+
+       case VPU_IOC_RD_ENC: {
+               vpu_read_enc(regs_enc);
+               if (copy_to_user((void __user *)arg, regs_enc, SIZE_REG(REG_NUM_ENC)))
+                       return -EFAULT;
+               break;
+       }
+
+       case VPU_IOC_RD_PP: {
+               vpu_read_pp(regs_pp);
+               if (copy_to_user((void __user *)arg, regs_pp, SIZE_REG(REG_NUM_PP)))
+                       return -EFAULT;
+               break;
+       }
+
+
+       case VPU_IOC_CLS_IRQ: {
+               return vpu_clear_irqs(arg);
+               break;
+       }
+
        default:
                return -ENOTTY;
        }
@@ -185,6 +541,7 @@ static int vpu_fasync(int fd, struct file *filp, int mode)
 
 static int vpu_release(struct inode *inode, struct file *filp)
 {
+       msleep(50);
        /* remove this filp from the asynchronusly notified filp's */
        vpu_fasync(-1, filp, 0);
 
@@ -223,7 +580,7 @@ static int vpu_reserve_io(void)
        }
 
        dec_dev.hwregs =
-           (volatile u32 *)ioremap_nocache(dec_dev.iobaseaddr, dec_dev.iosize);
+               (volatile u32 *)ioremap_nocache(dec_dev.iobaseaddr, dec_dev.iosize);
 
        if (dec_dev.hwregs == NULL) {
                pr_info("failed to ioremap dec HW regs\n");
@@ -241,7 +598,7 @@ static int vpu_reserve_io(void)
        }
 
        enc_dev.hwregs =
-           (volatile u32 *)ioremap_nocache(enc_dev.iobaseaddr, enc_dev.iosize);
+               (volatile u32 *)ioremap_nocache(enc_dev.iobaseaddr, enc_dev.iosize);
 
        if (enc_dev.hwregs == NULL) {
                pr_info("failed to ioremap enc HW regs\n");
@@ -286,7 +643,7 @@ static irqreturn_t hx170dec_isr(int irq, void *dev_id)
 
        /* interrupt status register read */
        irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
-       irq_status_pp = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
+       irq_status_pp  = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
 
        if (irq_status_dec & DEC_INTERRUPT_BIT) {
                /* clear dec IRQ */
@@ -410,11 +767,11 @@ static ssize_t vpu_read(struct file *filep, char __user *buf,
 static const struct file_operations vpu_fops = {
        .read           = vpu_read,
        .poll           = vpu_poll,
-       .unlocked_ioctl = vpu_ioctl,
+       .unlocked_ioctl = vpu_ioctl,
        .mmap           = vpu_mmap,
        .open           = vpu_open,
        .release        = vpu_release,
-       .fasync         = vpu_fasync,
+       .fasync         = vpu_fasync,
 };
 
 static struct miscdevice vpu_misc_device = {
@@ -433,6 +790,7 @@ static void vpu_shutdown(struct platform_device *pdev)
 static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
 {
        bool enabled = client.enabled;
+       mdelay(50);
        vpu_power_off();
        client.enabled = enabled;
        return 0;
@@ -448,8 +806,8 @@ static int vpu_resume(struct platform_device *pdev)
 }
 
 static struct platform_device vpu_pm_device = {
-       .name          = "vpu",
-       .id            = -1,
+       .name              = "vpu",
+       .id                = -1,
 };
 
 static struct platform_driver vpu_pm_driver = {
@@ -514,6 +872,9 @@ static int __init vpu_init(void)
        platform_driver_probe(&vpu_pm_driver, NULL);
        pr_info("init success\n");
 
+       memset(regs_enc, 0, sizeof(regs_enc));
+       memset(regs_dec, 0, sizeof(regs_dec));
+
        return 0;
 
 err_register:
@@ -589,7 +950,7 @@ static int proc_vpu_open(struct inode *inode, struct file *file)
 static const struct file_operations proc_vpu_fops = {
        .open           = proc_vpu_open,
        .read           = seq_read,
-       .llseek         = seq_lseek,
+       .llseek         = seq_lseek,
        .release        = single_release,
 };