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
1 /* arch/arm/mach-rk29/vpu.c
2  *
3  * Copyright (C) 2010 ROCKCHIP, Inc.
4  * author: chenhengming chm@rock-chips.com
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #ifdef CONFIG_RK29_VPU_DEBUG
18 #define DEBUG
19 #define pr_fmt(fmt) "VPU_SERVICE: %s: " fmt, __func__
20 #else
21 #define pr_fmt(fmt) "VPU_SERVICE: " fmt
22 #endif
23
24
25 #include <linux/clk.h>
26 #include <linux/delay.h>
27 #include <linux/init.h>
28 #include <linux/interrupt.h>
29 #include <linux/io.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/fs.h>
33 #include <linux/ioport.h>
34 #include <linux/miscdevice.h>
35 #include <linux/mm.h>
36 #include <linux/poll.h>
37 #include <linux/platform_device.h>
38 #include <linux/slab.h>
39 #include <linux/timer.h>
40
41 #include <asm/uaccess.h>
42
43 #include <mach/irqs.h>
44 #include <mach/vpu_service.h>
45 #include <mach/rk29_iomap.h>
46 #include <mach/pmu.h>
47 #include <mach/cru.h>
48
49
50 #define DEC_INTERRUPT_REGISTER                  1
51 #define PP_INTERRUPT_REGISTER                   60
52 #define ENC_INTERRUPT_REGISTER                  1
53
54 #define DEC_INTERRUPT_BIT                        0x100
55 #define PP_INTERRUPT_BIT                         0x100
56 #define ENC_INTERRUPT_BIT                        0x1
57
58 #define REG_NUM_DEC                             (60)
59 #define REG_NUM_PP                              (41)
60 #define REG_NUM_ENC                             (96)
61 #define REG_NUM_DEC_PP                          (REG_NUM_DEC+REG_NUM_PP)
62 #define SIZE_REG(reg)                           ((reg)*4)
63
64 #define DEC_IO_SIZE                             ((100 + 1) * 4) /* bytes */
65 #define ENC_IO_SIZE                             (96 * 4)        /* bytes */
66 static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 };
67 static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 };
68
69 #define VPU_REG_EN_ENC                          14
70 #define VPU_REG_ENC_GATE                        2
71 #define VPU_REG_ENC_GATE_BIT                    (1<<4)
72
73 #define VPU_REG_EN_DEC                          1
74 #define VPU_REG_DEC_GATE                        2
75 #define VPU_REG_DEC_GATE_BIT                    (1<<10)
76 #define VPU_REG_EN_PP                           0
77 #define VPU_REG_PP_GATE                         1
78 #define VPU_REG_PP_GATE_BIT                     (1<<8)
79 #define VPU_REG_EN_DEC_PP                       1
80 #define VPU_REG_DEC_PP_GATE                     61
81 #define VPU_REG_DEC_PP_GATE_BIT                 (1<<8)
82
83
84 /**
85  * struct for process session which connect to vpu
86  *
87  * @author ChenHengming (2011-5-3)
88  */
89 typedef struct vpu_session {
90         VPU_CLIENT_TYPE         type;
91         /* a linked list of data so we can access them for debugging */
92         struct list_head        list_session;
93         /* a linked list of register data waiting for process */
94         struct list_head        waiting;
95         /* a linked list of register data in processing */
96         struct list_head        running;
97         /* a linked list of register data processed */
98         struct list_head        done;
99         wait_queue_head_t       wait;
100         pid_t                   pid;
101         atomic_t                task_running;
102 } vpu_session;
103
104 /**
105  * struct for process register set
106  *
107  * @author ChenHengming (2011-5-4)
108  */
109 typedef struct vpu_reg {
110         VPU_CLIENT_TYPE         type;
111         vpu_session             *session;
112         struct list_head        session_link;           /* link to vpu service session */
113         struct list_head        status_link;            /* link to register set list */
114         unsigned long           size;
115         unsigned long           reg[VPU_REG_NUM_DEC_PP];
116 } vpu_reg;
117
118 typedef struct vpu_device {
119         unsigned long           iobaseaddr;
120         unsigned int            iosize;
121         volatile u32            *hwregs;
122 } vpu_device;
123
124 typedef struct vpu_service_info {
125         spinlock_t              lock;
126         struct timer_list       timer;                  /* timer for power off */
127         struct list_head        waiting;                /* link to link_reg in struct vpu_reg */
128         struct list_head        running;                /* link to link_reg in struct vpu_reg */
129         struct list_head        done;                   /* link to link_reg in struct vpu_reg */
130         struct list_head        session;                /* link to list_session in struct vpu_session */
131         atomic_t                total_running;
132         bool                    enabled;
133         vpu_reg                 *reg_codec;
134         vpu_reg                 *reg_pproc;
135         vpu_reg                 *reg_resev;
136         VPUHwDecConfig_t        dec_config;
137         VPUHwEncConfig_t        enc_config;
138 } vpu_service_info;
139
140 typedef struct vpu_request
141 {
142         unsigned long   *req;
143         unsigned long   size;
144 } vpu_request;
145
146 static struct clk *aclk_vepu;
147 static struct clk *hclk_vepu;
148 static struct clk *aclk_ddr_vepu;
149 static struct clk *hclk_cpu_vcodec;
150 static vpu_service_info service;
151 static vpu_device       dec_dev;
152 static vpu_device       enc_dev;
153
154 #define POWER_OFF_DELAY 4*HZ /* 4s */
155 #define TIMEOUT_DELAY   2*HZ /* 2s */
156
157 static void vpu_get_clk(void)
158 {
159         aclk_vepu       = clk_get(NULL, "aclk_vepu");
160         hclk_vepu       = clk_get(NULL, "hclk_vepu");
161         aclk_ddr_vepu   = clk_get(NULL, "aclk_ddr_vepu");
162         hclk_cpu_vcodec = clk_get(NULL, "hclk_cpu_vcodec");
163 }
164
165 static void vpu_put_clk(void)
166 {
167         clk_put(aclk_vepu);
168         clk_put(hclk_vepu);
169         clk_put(aclk_ddr_vepu);
170         clk_put(hclk_cpu_vcodec);
171 }
172
173 static void vpu_reset(void)
174 {
175         clk_disable(aclk_ddr_vepu);
176         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
177         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);
178         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);
179         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);
180         mdelay(10);
181         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);
182         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);
183         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);
184         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);
185         clk_enable(aclk_ddr_vepu);
186         service.reg_codec = NULL;
187         service.reg_pproc = NULL;
188         service.reg_resev = NULL;
189 }
190
191 static void reg_deinit(vpu_reg *reg);
192 static void vpu_service_session_clear(vpu_session *session)
193 {
194         vpu_reg *reg, *n;
195         list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
196                 reg_deinit(reg);
197         }
198         list_for_each_entry_safe(reg, n, &session->running, session_link) {
199                 reg_deinit(reg);
200         }
201         list_for_each_entry_safe(reg, n, &session->done, session_link) {
202                 reg_deinit(reg);
203         }
204 }
205
206 static void vpu_service_dump(void)
207 {
208         int running;
209         vpu_reg *reg, *reg_tmp;
210         vpu_session *session, *session_tmp;
211
212         running = atomic_read(&service.total_running);
213         printk("total_running %d\n", running);
214
215         printk("reg_codec 0x%.8x\n", (unsigned int)service.reg_codec);
216         printk("reg_pproc 0x%.8x\n", (unsigned int)service.reg_pproc);
217         printk("reg_resev 0x%.8x\n", (unsigned int)service.reg_resev);
218
219         list_for_each_entry_safe(session, session_tmp, &service.session, list_session) {
220                 printk("session pid %d type %d:\n", session->pid, session->type);
221                 running = atomic_read(&session->task_running);
222                 printk("task_running %d\n", running);
223                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {
224                         printk("waiting register set 0x%.8x\n", (unsigned int)reg);
225                 }
226                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {
227                         printk("running register set 0x%.8x\n", (unsigned int)reg);
228                 }
229                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {
230                         printk("done    register set 0x%.8x\n", (unsigned int)reg);
231                 }
232         }
233 }
234
235 static void vpu_service_power_off(void)
236 {
237         int total_running;
238
239         if (!service.enabled)
240                 return;
241
242         service.enabled = false;
243         total_running = atomic_read(&service.total_running);
244         if (total_running) {
245                 pr_alert("power off when %d task running!!\n", total_running);
246                 mdelay(50);
247                 pr_alert("delay 50 ms for running task\n");
248                 vpu_service_dump();
249         }
250
251         printk("vpu: power off...");
252         pmu_set_power_domain(PD_VCODEC, false);
253         udelay(10);
254         clk_disable(hclk_cpu_vcodec);
255         clk_disable(aclk_ddr_vepu);
256         clk_disable(hclk_vepu);
257         clk_disable(aclk_vepu);
258         printk("done\n");
259 }
260
261 static void vpu_service_power_off_work_func(unsigned long data)
262 {
263         printk("delayed ");
264         vpu_service_power_off();
265 }
266
267 static void vpu_service_power_maintain(void)
268 {
269         if (service.enabled) {
270                 mod_timer(&service.timer, jiffies + POWER_OFF_DELAY);
271         } else {
272                 pr_err("maintain power when power is off!\n");
273         }
274 }
275
276 static void vpu_service_power_on(void)
277 {
278         if (!service.enabled) {
279                 service.enabled = true;
280                 printk("vpu: power on\n");
281
282                 clk_enable(aclk_vepu);
283                 clk_enable(hclk_vepu);
284                 clk_enable(hclk_cpu_vcodec);
285                 udelay(10);
286                 pmu_set_power_domain(PD_VCODEC, true);
287                 udelay(10);
288                 clk_enable(aclk_ddr_vepu);
289                 init_timer(&service.timer);
290                 service.timer.expires = jiffies + POWER_OFF_DELAY;
291                 service.timer.function = vpu_service_power_off_work_func;
292                 add_timer(&service.timer);
293         } else {
294                 vpu_service_power_maintain();
295         }
296 }
297
298 static vpu_reg *reg_init(vpu_session *session, void __user *src, unsigned long size)
299 {
300         unsigned long flag;
301         vpu_reg *reg = kmalloc(sizeof(vpu_reg), GFP_KERNEL);
302         if (NULL == reg) {
303                 pr_err("kmalloc fail in reg_init\n");
304                 return NULL;
305         }
306
307         reg->session = session;
308         reg->type = session->type;
309         reg->size = size;
310         INIT_LIST_HEAD(&reg->session_link);
311         INIT_LIST_HEAD(&reg->status_link);
312
313         if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {
314                 pr_err("copy_from_user failed in reg_init\n");
315                 kfree(reg);
316                 return NULL;
317         }
318
319         spin_lock_irqsave(&service.lock, flag);
320         list_add_tail(&reg->status_link, &service.waiting);
321         list_add_tail(&reg->session_link, &session->waiting);
322         spin_unlock_irqrestore(&service.lock, flag);
323
324         return reg;
325 }
326
327 static void reg_deinit(vpu_reg *reg)
328 {
329         list_del_init(&reg->session_link);
330         list_del_init(&reg->status_link);
331         kfree(reg);
332         if (reg == service.reg_codec) service.reg_codec = NULL;
333         if (reg == service.reg_pproc) service.reg_pproc = NULL;
334 }
335
336 static void reg_from_wait_to_run(vpu_reg *reg)
337 {
338         list_del_init(&reg->status_link);
339         list_add_tail(&reg->status_link, &service.running);
340
341         list_del_init(&reg->session_link);
342         list_add_tail(&reg->session_link, &reg->session->running);
343 }
344
345 static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count)
346 {
347         int i;
348         u32 *dst = (u32 *)&reg->reg[0];
349         for (i = 0; i < count; i++)
350                 *dst++ = *src++;
351 }
352
353 static void reg_from_run_to_done(vpu_reg *reg)
354 {
355         spin_lock(&service.lock);
356         list_del_init(&reg->status_link);
357         list_add_tail(&reg->status_link, &service.done);
358
359         list_del_init(&reg->session_link);
360         list_add_tail(&reg->session_link, &reg->session->done);
361
362         switch (reg->type) {
363         case VPU_ENC : {
364                 service.reg_codec = NULL;
365                 reg_copy_from_hw(reg, enc_dev.hwregs, REG_NUM_ENC);
366                 break;
367         }
368         case VPU_DEC : {
369                 service.reg_codec = NULL;
370                 reg_copy_from_hw(reg, dec_dev.hwregs, REG_NUM_DEC);
371                 break;
372         }
373         case VPU_PP : {
374                 service.reg_pproc = NULL;
375                 reg_copy_from_hw(reg, dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_PP);
376                 dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
377                 break;
378         }
379         case VPU_DEC_PP : {
380                 service.reg_codec = NULL;
381                 service.reg_pproc = NULL;
382                 reg_copy_from_hw(reg, dec_dev.hwregs, REG_NUM_DEC_PP);
383                 dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;
384                 break;
385         }
386         default : {
387                 pr_err("copy reg from hw with unknown type %d\n", reg->type);
388                 break;
389         }
390         }
391         atomic_sub(1, &reg->session->task_running);
392         atomic_sub(1, &service.total_running);
393         wake_up_interruptible_sync(&reg->session->wait);
394         spin_unlock(&service.lock);
395 }
396
397 void reg_copy_to_hw(vpu_reg *reg)
398 {
399         int i;
400         u32 *src = (u32 *)&reg->reg[0];
401         atomic_add(1, &service.total_running);
402         atomic_add(1, &reg->session->task_running);
403         switch (reg->type) {
404         case VPU_ENC : {
405                 u32 *dst = (u32 *)enc_dev.hwregs;
406                 service.reg_codec = reg;
407
408                 dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;
409
410                 for (i = 0; i < VPU_REG_EN_ENC; i++)
411                         dst[i] = src[i];
412
413                 for (i = VPU_REG_EN_ENC + 1; i < REG_NUM_ENC; i++)
414                         dst[i] = src[i];
415
416                 dsb();
417
418                 dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;
419                 dst[VPU_REG_EN_ENC]   = src[VPU_REG_EN_ENC];
420         } break;
421         case VPU_DEC : {
422                 u32 *dst = (u32 *)dec_dev.hwregs;
423                 service.reg_codec = reg;
424
425                 for (i = REG_NUM_DEC - 1; i > VPU_REG_DEC_GATE; i--)
426                         dst[i] = src[i];
427
428                 dsb();
429
430                 dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;
431                 dst[VPU_REG_EN_DEC]   = src[VPU_REG_EN_DEC];
432         } break;
433         case VPU_PP : {
434                 u32 *dst = (u32 *)dec_dev.hwregs + PP_INTERRUPT_REGISTER;
435                 service.reg_pproc = reg;
436
437                 dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;
438
439                 for (i = VPU_REG_PP_GATE + 1; i < REG_NUM_PP; i++)
440                         dst[i] = src[i];
441
442                 dsb();
443
444                 dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];
445         } break;
446         case VPU_DEC_PP : {
447                 u32 *dst = (u32 *)dec_dev.hwregs;
448                 service.reg_codec = reg;
449                 service.reg_pproc = reg;
450
451                 for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_DEC_PP; i++)
452                         dst[i] = src[i];
453
454                 dst[VPU_REG_EN_DEC_PP]   = src[VPU_REG_EN_DEC_PP] | 0x2;
455                 dsb();
456
457                 dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;
458                 dst[VPU_REG_DEC_GATE]    = src[VPU_REG_DEC_GATE]    | VPU_REG_DEC_GATE_BIT;
459                 dst[VPU_REG_EN_DEC]      = src[VPU_REG_EN_DEC];
460         } break;
461         default : {
462                 pr_err("unsupport session type %d", reg->type);
463                 atomic_sub(1, &service.total_running);
464                 atomic_sub(1, &reg->session->task_running);
465                 break;
466         }
467         }
468 }
469
470 static void try_set_reg(void)
471 {
472         unsigned long flag;
473         // first get reg from reg list
474         spin_lock_irqsave(&service.lock, flag);
475         if (!list_empty(&service.waiting)) {
476                 vpu_reg *reg = list_entry(service.waiting.next, vpu_reg, status_link);
477
478                 vpu_service_power_maintain();
479                 if (((VPU_DEC_PP == reg->type) && (NULL == service.reg_codec) && (NULL == service.reg_pproc)) ||
480                         ((VPU_DEC == reg->type) && (NULL == service.reg_codec)) ||
481                         ((VPU_PP  == reg->type) && (NULL == service.reg_pproc)) ||
482                         ((VPU_ENC == reg->type) && (NULL == service.reg_codec))) {
483                         reg_from_wait_to_run(reg);
484                         reg_copy_to_hw(reg);
485                 }
486         }
487         spin_unlock_irqrestore(&service.lock, flag);
488 }
489
490 static int return_reg(vpu_reg *reg, u32 __user *dst)
491 {
492         int ret = 0;
493         switch (reg->type) {
494         case VPU_ENC : {
495                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_ENC)))
496                         ret = -EFAULT;
497                 break;
498         }
499         case VPU_DEC : {
500                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_DEC)))
501                         ret = -EFAULT;
502                 break;
503         }
504         case VPU_PP : {
505                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_PP)))
506                         ret = -EFAULT;
507                 break;
508         }
509         case VPU_DEC_PP : {
510                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_DEC_PP)))
511                         ret = -EFAULT;
512                 break;
513         }
514         default : {
515                 ret = -EFAULT;
516                 pr_err("copy reg to user with unknown type %d\n", reg->type);
517                 break;
518         }
519         }
520         reg_deinit(reg);
521         return ret;
522 }
523
524 static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
525 {
526         vpu_session *session = (vpu_session *)filp->private_data;
527         if (NULL == session) {
528                 return -EINVAL;
529         }
530
531         switch (cmd) {
532         case VPU_IOC_SET_CLIENT_TYPE : {
533         session->type = (VPU_CLIENT_TYPE)arg;
534                 break;
535         }
536         case VPU_IOC_GET_HW_FUSE_STATUS : {
537                 vpu_request req;
538                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {
539                         pr_err("VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n");
540                         return -EFAULT;
541                 } else {
542                         if (VPU_ENC != session->type) {
543                                 if (copy_to_user((void __user *)req.req, &service.dec_config, sizeof(VPUHwDecConfig_t))) {
544                                         pr_err("VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);
545                                         return -EFAULT;
546                                 }
547                         } else {
548                                 if (copy_to_user((void __user *)req.req, &service.enc_config, sizeof(VPUHwEncConfig_t))) {
549                                         pr_err("VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);
550                                         return -EFAULT;
551                                 }
552                         }
553                 }
554
555                 break;
556         }
557         case VPU_IOC_SET_REG : {
558                 vpu_request req;
559                 vpu_reg *reg;
560                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {
561                         pr_err("VPU_IOC_SET_REG copy_from_user failed\n");
562                         return -EFAULT;
563                 }
564
565                 reg = reg_init(session, (void __user *)req.req, req.size);
566                 if (NULL == reg) {
567                         return -EFAULT;
568                 } else {
569                         vpu_service_power_on();
570                         try_set_reg();
571                 }
572
573                 break;
574         }
575         case VPU_IOC_GET_REG : {
576                 vpu_request req;
577                 vpu_reg *reg;
578                 unsigned long flag;
579                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {
580                         pr_err("VPU_IOC_GET_REG copy_from_user failed\n");
581                         return -EFAULT;
582                 } else {
583                         int ret = wait_event_interruptible_timeout(session->wait, !list_empty(&session->done), TIMEOUT_DELAY);
584                         if (unlikely(ret < 0)) {
585                                 pr_err("pid %d wait task ret %d\n", session->pid, ret);
586                         } else if (0 == ret) {
587                                 pr_err("pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));
588                                 ret = -ETIMEDOUT;
589                         }
590                         spin_lock_irqsave(&service.lock, flag);
591                         if (ret < 0) {
592                                 int task_running = atomic_read(&session->task_running);
593                                 vpu_service_dump();
594                                 if (task_running) {
595                                         atomic_set(&session->task_running, 0);
596                                         atomic_sub(task_running, &service.total_running);
597                                         printk("%d task is running but not return, reset hardware...", task_running);
598                                         vpu_reset();
599                                         printk("done\n");
600                                 }
601                                 vpu_service_session_clear(session);
602                                 spin_unlock_irqrestore(&service.lock, flag);
603                                 return ret;
604                         }
605                         spin_unlock_irqrestore(&service.lock, flag);
606                 }
607                 spin_lock_irqsave(&service.lock, flag);
608                 reg = list_entry(session->done.next, vpu_reg, session_link);
609                 return_reg(reg, (u32 __user *)req.req);
610                 spin_unlock_irqrestore(&service.lock, flag);
611                 break;
612         }
613         default : {
614                 pr_err("unknow vpu service ioctl cmd %x\n", cmd);
615                 break;
616         }
617         }
618
619         return 0;
620 }
621
622 static int vpu_service_check_hw_id(struct vpu_device * dev, const u16 *hwids, size_t num)
623 {
624         u32 hwid = readl(dev->hwregs);
625         pr_info("HW ID = 0x%08x\n", hwid);
626
627         hwid = (hwid >> 16) & 0xFFFF;   /* product version only */
628
629         while (num--) {
630                 if (hwid == hwids[num]) {
631                         pr_info("Compatible HW found at 0x%08lx\n", dev->iobaseaddr);
632                         return 1;
633                 }
634         }
635
636         pr_info("No Compatible HW found at 0x%08lx\n", dev->iobaseaddr);
637         return 0;
638 }
639
640 static void vpu_service_release_io(void)
641 {
642         if (dec_dev.hwregs)
643                 iounmap((void *)dec_dev.hwregs);
644         release_mem_region(dec_dev.iobaseaddr, dec_dev.iosize);
645
646         if (enc_dev.hwregs)
647                 iounmap((void *)enc_dev.hwregs);
648         release_mem_region(enc_dev.iobaseaddr, enc_dev.iosize);
649 }
650
651 static int vpu_service_reserve_io(void)
652 {
653         unsigned long iobaseaddr;
654         unsigned long iosize;
655
656         iobaseaddr      = dec_dev.iobaseaddr;
657         iosize          = dec_dev.iosize;
658
659         if (!request_mem_region(iobaseaddr, iosize, "vdpu_io")) {
660                 pr_info("failed to reserve dec HW regs\n");
661                 return -EBUSY;
662         }
663
664         dec_dev.hwregs = (volatile u32 *)ioremap_nocache(iobaseaddr, iosize);
665
666         if (dec_dev.hwregs == NULL) {
667                 pr_info("failed to ioremap dec HW regs\n");
668                 goto err;
669         }
670
671         /* check for correct HW */
672         if (!vpu_service_check_hw_id(&dec_dev, dec_hw_ids, ARRAY_SIZE(dec_hw_ids))) {
673                 goto err;
674         }
675
676         iobaseaddr      = enc_dev.iobaseaddr;
677         iosize          = enc_dev.iosize;
678
679         if (!request_mem_region(iobaseaddr, iosize, "hx280enc")) {
680                 pr_info("failed to reserve enc HW regs\n");
681                 goto err;
682         }
683
684         enc_dev.hwregs = (volatile u32 *)ioremap_nocache(iobaseaddr, iosize);
685
686         if (enc_dev.hwregs == NULL) {
687                 pr_info("failed to ioremap enc HW regs\n");
688                 goto err;
689         }
690
691         /* check for correct HW */
692         if (!vpu_service_check_hw_id(&enc_dev, enc_hw_ids, ARRAY_SIZE(enc_hw_ids))) {
693                 goto err;
694         }
695         return 0;
696
697 err:
698         vpu_service_release_io();
699         return -EBUSY;
700 }
701
702 static int vpu_service_open(struct inode *inode, struct file *filp)
703 {
704         vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL);
705         if (NULL == session) {
706                 pr_err("unable to allocate memory for vpu_session.");
707                 return -ENOMEM;
708         }
709
710         session->type   = VPU_TYPE_BUTT;
711         session->pid    = current->pid;
712         INIT_LIST_HEAD(&session->waiting);
713         INIT_LIST_HEAD(&session->running);
714         INIT_LIST_HEAD(&session->done);
715         INIT_LIST_HEAD(&session->list_session);
716         init_waitqueue_head(&session->wait);
717         /* no need to protect */
718         list_add_tail(&session->list_session, &service.session);
719         atomic_set(&session->task_running, 0);
720         filp->private_data = (void *)session;
721
722         pr_debug("dev opened\n");
723         return nonseekable_open(inode, filp);
724 }
725
726 static int vpu_service_release(struct inode *inode, struct file *filp)
727 {
728         int task_running;
729         unsigned long flag;
730         vpu_session *session = (vpu_session *)filp->private_data;
731         if (NULL == session)
732                 return -EINVAL;
733
734         task_running = atomic_read(&session->task_running);
735         if (task_running) {
736                 pr_err("vpu_service session %d still has %d task running when closing\n", session->pid, task_running);
737                 msleep(50);
738         }
739         wake_up_interruptible_sync(&session->wait);
740
741         spin_lock_irqsave(&service.lock, flag);
742         /* remove this filp from the asynchronusly notified filp's */
743         //vpu_service_fasync(-1, filp, 0);
744         list_del(&session->list_session);
745
746         vpu_service_session_clear(session);
747
748         kfree(session);
749         spin_unlock_irqrestore(&service.lock, flag);
750
751         pr_debug("dev closed\n");
752         return 0;
753 }
754
755 static const struct file_operations vpu_service_fops = {
756         .unlocked_ioctl = vpu_service_ioctl,
757         .open           = vpu_service_open,
758         .release        = vpu_service_release,
759         //.fasync       = vpu_service_fasync,
760 };
761
762 static struct miscdevice vpu_service_misc_device = {
763         .minor          = MISC_DYNAMIC_MINOR,
764         .name           = "vpu_service",
765         .fops           = &vpu_service_fops,
766 };
767
768 static void vpu_service_shutdown(struct platform_device *pdev)
769 {
770         pr_cont("shutdown...");
771         del_timer(&service.timer);
772         vpu_service_power_off();
773         pr_cont("done\n");
774 }
775
776 static int vpu_service_suspend(struct platform_device *pdev, pm_message_t state)
777 {
778         bool enabled;
779         pr_info("suspend...");
780         del_timer(&service.timer);
781         enabled = service.enabled;
782         vpu_service_power_off();
783         service.enabled = enabled;
784         return 0;
785 }
786
787 static int vpu_service_resume(struct platform_device *pdev)
788 {
789         pr_info("resume...");
790         if (service.enabled) {
791                 service.enabled = false;
792                 vpu_service_power_on();
793                 try_set_reg();
794         }
795         return 0;
796 }
797
798 static struct platform_device vpu_service_device = {
799         .name              = "vpu_service",
800         .id                = -1,
801 };
802
803 static struct platform_driver vpu_service_driver = {
804         .driver    = {
805                 .name  = "vpu_service",
806                 .owner = THIS_MODULE,
807         },
808         .shutdown  = vpu_service_shutdown,
809         .suspend   = vpu_service_suspend,
810         .resume    = vpu_service_resume,
811 };
812
813 static void get_hw_info(void)
814 {
815         VPUHwDecConfig_t *dec = &service.dec_config;
816         VPUHwEncConfig_t *enc = &service.enc_config;
817         u32 configReg   = dec_dev.hwregs[VPU_DEC_HWCFG0];
818         u32 asicID      = dec_dev.hwregs[0];
819
820         dec->h264Support    = (configReg >> DWL_H264_E) & 0x3U;
821         dec->jpegSupport    = (configReg >> DWL_JPEG_E) & 0x01U;
822         if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U))
823                 dec->jpegSupport = JPEG_PROGRESSIVE;
824         dec->mpeg4Support   = (configReg >> DWL_MPEG4_E) & 0x3U;
825         dec->vc1Support     = (configReg >> DWL_VC1_E) & 0x3U;
826         dec->mpeg2Support   = (configReg >> DWL_MPEG2_E) & 0x01U;
827         dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U;
828         dec->refBufSupport  = (configReg >> DWL_REF_BUFF_E) & 0x01U;
829         dec->vp6Support     = (configReg >> DWL_VP6_E) & 0x01U;
830         dec->maxDecPicWidth = configReg & 0x07FFU;
831
832         /* 2nd Config register */
833         configReg   = dec_dev.hwregs[VPU_DEC_HWCFG1];
834         if (dec->refBufSupport) {
835                 if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U)
836                         dec->refBufSupport |= 2;
837                 if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U)
838                         dec->refBufSupport |= 4;
839         }
840         dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U;
841         dec->vp7Support     = (configReg >> DWL_VP7_E) & 0x01U;
842         dec->vp8Support     = (configReg >> DWL_VP8_E) & 0x01U;
843         dec->avsSupport     = (configReg >> DWL_AVS_E) & 0x01U;
844
845         /* JPEG xtensions */
846         if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) {
847                 dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U;
848         } else {
849                 dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED;
850         }
851
852         if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) ) {
853                 dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U;
854         } else {
855                 dec->rvSupport = RV_NOT_SUPPORTED;
856         }
857
858         dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U;
859
860         if (dec->refBufSupport && (asicID >> 16) == 0x6731U ) {
861                 dec->refBufSupport |= 8; /* enable HW support for offset */
862         }
863
864         {
865         VPUHwFuseStatus_t hwFuseSts;
866         /* Decoder fuse configuration */
867         u32 fuseReg = dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];
868
869         hwFuseSts.h264SupportFuse = (fuseReg >> DWL_H264_FUSE_E) & 0x01U;
870         hwFuseSts.mpeg4SupportFuse = (fuseReg >> DWL_MPEG4_FUSE_E) & 0x01U;
871         hwFuseSts.mpeg2SupportFuse = (fuseReg >> DWL_MPEG2_FUSE_E) & 0x01U;
872         hwFuseSts.sorensonSparkSupportFuse = (fuseReg >> DWL_SORENSONSPARK_FUSE_E) & 0x01U;
873         hwFuseSts.jpegSupportFuse = (fuseReg >> DWL_JPEG_FUSE_E) & 0x01U;
874         hwFuseSts.vp6SupportFuse = (fuseReg >> DWL_VP6_FUSE_E) & 0x01U;
875         hwFuseSts.vc1SupportFuse = (fuseReg >> DWL_VC1_FUSE_E) & 0x01U;
876         hwFuseSts.jpegProgSupportFuse = (fuseReg >> DWL_PJPEG_FUSE_E) & 0x01U;
877         hwFuseSts.rvSupportFuse = (fuseReg >> DWL_RV_FUSE_E) & 0x01U;
878         hwFuseSts.avsSupportFuse = (fuseReg >> DWL_AVS_FUSE_E) & 0x01U;
879         hwFuseSts.vp7SupportFuse = (fuseReg >> DWL_VP7_FUSE_E) & 0x01U;
880         hwFuseSts.vp8SupportFuse = (fuseReg >> DWL_VP8_FUSE_E) & 0x01U;
881         hwFuseSts.customMpeg4SupportFuse = (fuseReg >> DWL_CUSTOM_MPEG4_FUSE_E) & 0x01U;
882         hwFuseSts.mvcSupportFuse = (fuseReg >> DWL_MVC_FUSE_E) & 0x01U;
883
884         /* check max. decoder output width */
885
886         if (fuseReg & 0x8000U)
887                 hwFuseSts.maxDecPicWidthFuse = 1920;
888         else if (fuseReg & 0x4000U)
889                 hwFuseSts.maxDecPicWidthFuse = 1280;
890         else if (fuseReg & 0x2000U)
891                 hwFuseSts.maxDecPicWidthFuse = 720;
892         else if (fuseReg & 0x1000U)
893                 hwFuseSts.maxDecPicWidthFuse = 352;
894         else    /* remove warning */
895                 hwFuseSts.maxDecPicWidthFuse = 352;
896
897         hwFuseSts.refBufSupportFuse = (fuseReg >> DWL_REF_BUFF_FUSE_E) & 0x01U;
898
899         /* Pp configuration */
900         configReg = dec_dev.hwregs[VPU_PP_HW_SYNTH_CFG];
901
902         if ((configReg >> DWL_PP_E) & 0x01U) {
903                 dec->ppSupport = 1;
904                 dec->maxPpOutPicWidth = configReg & 0x07FFU;
905                 /*pHwCfg->ppConfig = (configReg >> DWL_CFG_E) & 0x0FU; */
906                 dec->ppConfig = configReg;
907         } else {
908                 dec->ppSupport = 0;
909                 dec->maxPpOutPicWidth = 0;
910                 dec->ppConfig = 0;
911         }
912
913         /* check the HW versio */
914         if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) {
915                 /* Pp configuration */
916                 configReg = dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];
917
918                 if ((configReg >> DWL_PP_E) & 0x01U) {
919                         /* Pp fuse configuration */
920                         u32 fuseRegPp = dec_dev.hwregs[VPU_PP_HW_FUSE_CFG];
921
922                         if ((fuseRegPp >> DWL_PP_FUSE_E) & 0x01U) {
923                                 hwFuseSts.ppSupportFuse = 1;
924                                 /* check max. pp output width */
925                                 if      (fuseRegPp & 0x8000U) hwFuseSts.maxPpOutPicWidthFuse = 1920;
926                                 else if (fuseRegPp & 0x4000U) hwFuseSts.maxPpOutPicWidthFuse = 1280;
927                                 else if (fuseRegPp & 0x2000U) hwFuseSts.maxPpOutPicWidthFuse = 720;
928                                 else if (fuseRegPp & 0x1000U) hwFuseSts.maxPpOutPicWidthFuse = 352;
929                                 else                          hwFuseSts.maxPpOutPicWidthFuse = 352;
930                                 hwFuseSts.ppConfigFuse = fuseRegPp;
931                         } else {
932                                 hwFuseSts.ppSupportFuse = 0;
933                                 hwFuseSts.maxPpOutPicWidthFuse = 0;
934                                 hwFuseSts.ppConfigFuse = 0;
935                         }
936                 } else {
937                         hwFuseSts.ppSupportFuse = 0;
938                         hwFuseSts.maxPpOutPicWidthFuse = 0;
939                         hwFuseSts.ppConfigFuse = 0;
940                 }
941
942                 if (dec->maxDecPicWidth > hwFuseSts.maxDecPicWidthFuse)
943                         dec->maxDecPicWidth = hwFuseSts.maxDecPicWidthFuse;
944                 if (dec->maxPpOutPicWidth > hwFuseSts.maxPpOutPicWidthFuse)
945                         dec->maxPpOutPicWidth = hwFuseSts.maxPpOutPicWidthFuse;
946                 if (!hwFuseSts.h264SupportFuse) dec->h264Support = H264_NOT_SUPPORTED;
947                 if (!hwFuseSts.mpeg4SupportFuse) dec->mpeg4Support = MPEG4_NOT_SUPPORTED;
948                 if (!hwFuseSts.customMpeg4SupportFuse) dec->customMpeg4Support = MPEG4_CUSTOM_NOT_SUPPORTED;
949                 if (!hwFuseSts.jpegSupportFuse) dec->jpegSupport = JPEG_NOT_SUPPORTED;
950                 if ((dec->jpegSupport == JPEG_PROGRESSIVE) && !hwFuseSts.jpegProgSupportFuse)
951                         dec->jpegSupport = JPEG_BASELINE;
952                 if (!hwFuseSts.mpeg2SupportFuse) dec->mpeg2Support = MPEG2_NOT_SUPPORTED;
953                 if (!hwFuseSts.vc1SupportFuse) dec->vc1Support = VC1_NOT_SUPPORTED;
954                 if (!hwFuseSts.vp6SupportFuse) dec->vp6Support = VP6_NOT_SUPPORTED;
955                 if (!hwFuseSts.vp7SupportFuse) dec->vp7Support = VP7_NOT_SUPPORTED;
956                 if (!hwFuseSts.vp8SupportFuse) dec->vp8Support = VP8_NOT_SUPPORTED;
957                 if (!hwFuseSts.ppSupportFuse) dec->ppSupport = PP_NOT_SUPPORTED;
958
959                 /* check the pp config vs fuse status */
960                 if ((dec->ppConfig & 0xFC000000) && ((hwFuseSts.ppConfigFuse & 0xF0000000) >> 5)) {
961                         u32 deInterlace = ((dec->ppConfig & PP_DEINTERLACING) >> 25);
962                         u32 alphaBlend  = ((dec->ppConfig & PP_ALPHA_BLENDING) >> 24);
963                         u32 deInterlaceFuse = (((hwFuseSts.ppConfigFuse >> 5) & PP_DEINTERLACING) >> 25);
964                         u32 alphaBlendFuse  = (((hwFuseSts.ppConfigFuse >> 5) & PP_ALPHA_BLENDING) >> 24);
965
966                         if (deInterlace && !deInterlaceFuse) dec->ppConfig &= 0xFD000000;
967                         if (alphaBlend && !alphaBlendFuse) dec->ppConfig &= 0xFE000000;
968                 }
969                 if (!hwFuseSts.sorensonSparkSupportFuse) dec->sorensonSparkSupport = SORENSON_SPARK_NOT_SUPPORTED;
970                 if (!hwFuseSts.refBufSupportFuse)   dec->refBufSupport = REF_BUF_NOT_SUPPORTED;
971                 if (!hwFuseSts.rvSupportFuse)       dec->rvSupport = RV_NOT_SUPPORTED;
972                 if (!hwFuseSts.avsSupportFuse)      dec->avsSupport = AVS_NOT_SUPPORTED;
973                 if (!hwFuseSts.mvcSupportFuse)      dec->mvcSupport = MVC_NOT_SUPPORTED;
974         }
975         }
976         configReg = enc_dev.hwregs[63];
977         enc->maxEncodedWidth = configReg & ((1 << 11) - 1);
978         enc->h264Enabled = (configReg >> 27) & 1;
979         enc->mpeg4Enabled = (configReg >> 26) & 1;
980         enc->jpegEnabled = (configReg >> 25) & 1;
981         enc->vsEnabled = (configReg >> 24) & 1;
982         enc->rgbEnabled = (configReg >> 28) & 1;
983         enc->busType = (configReg >> 20) & 15;
984         enc->synthesisLanguage = (configReg >> 16) & 15;
985         enc->busWidth = (configReg >> 12) & 15;
986 }
987
988 static irqreturn_t vdpu_isr(int irq, void *dev_id)
989 {
990         vpu_device *dev = (vpu_device *) dev_id;
991         u32 irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
992         u32 irq_status_pp  = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
993
994         pr_debug("vdpu_isr dec %x pp %x\n", irq_status_dec, irq_status_pp);
995
996         if (irq_status_dec & DEC_INTERRUPT_BIT) {
997                 irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
998                 if ((irq_status_dec & 0x40001) == 0x40001)
999                 {
1000                         do {
1001                                 irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
1002                         } while ((irq_status_dec & 0x40001) == 0x40001);
1003                 }
1004                 /* clear dec IRQ */
1005                 writel(irq_status_dec & (~DEC_INTERRUPT_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER);
1006                 pr_debug("DEC IRQ received!\n");
1007                 if (NULL == service.reg_codec) {
1008                         pr_err("dec isr with no task waiting\n");
1009                 } else {
1010                         reg_from_run_to_done(service.reg_codec);
1011                 }
1012         }
1013
1014         if (irq_status_pp & PP_INTERRUPT_BIT) {
1015                 /* clear pp IRQ */
1016                 writel(irq_status_pp & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
1017                 pr_debug("PP IRQ received!\n");
1018                 if (NULL == service.reg_pproc) {
1019                         pr_err("pp isr with no task waiting\n");
1020                 } else {
1021                         reg_from_run_to_done(service.reg_pproc);
1022                 }
1023         }
1024         try_set_reg();
1025         return IRQ_HANDLED;
1026 }
1027
1028 static irqreturn_t vepu_isr(int irq, void *dev_id)
1029 {
1030         struct vpu_device *dev = (struct vpu_device *) dev_id;
1031         u32 irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER);
1032
1033         pr_debug("enc_isr\n");
1034
1035         if (likely(irq_status & ENC_INTERRUPT_BIT)) {
1036                 /* clear enc IRQ */
1037                 writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);
1038                 pr_debug("ENC IRQ received!\n");
1039                 if (NULL == service.reg_codec) {
1040                         pr_err("enc isr with no task waiting\n");
1041                 } else {
1042                         reg_from_run_to_done(service.reg_codec);
1043                 }
1044         }
1045         try_set_reg();
1046         return IRQ_HANDLED;
1047 }
1048
1049 static int __init vpu_service_init(void)
1050 {
1051         int ret;
1052
1053         pr_debug("baseaddr = 0x%08x vdpu irq = %d vepu irq = %d\n", RK29_VCODEC_PHYS, IRQ_VDPU, IRQ_VEPU);
1054
1055         dec_dev.iobaseaddr      = RK29_VCODEC_PHYS + 0x200;
1056         dec_dev.iosize          = DEC_IO_SIZE;
1057         enc_dev.iobaseaddr      = RK29_VCODEC_PHYS;
1058         enc_dev.iosize          = ENC_IO_SIZE;
1059
1060         INIT_LIST_HEAD(&service.waiting);
1061         INIT_LIST_HEAD(&service.running);
1062         INIT_LIST_HEAD(&service.done);
1063         INIT_LIST_HEAD(&service.session);
1064         spin_lock_init(&service.lock);
1065         service.reg_codec       = NULL;
1066         service.reg_pproc       = NULL;
1067         atomic_set(&service.total_running, 0);
1068         service.enabled         = false;
1069
1070         vpu_get_clk();
1071         vpu_service_power_on();
1072
1073         ret = vpu_service_reserve_io();
1074         if (ret < 0) {
1075                 pr_err("reserve io failed\n");
1076                 goto err_reserve_io;
1077         }
1078
1079         /* get the IRQ line */
1080         ret = request_irq(IRQ_VDPU, vdpu_isr, IRQF_SHARED, "vdpu", (void *)&dec_dev);
1081         if (ret) {
1082                 pr_err("can't request vdpu irq %d\n", IRQ_VDPU);
1083                 goto err_req_vdpu_irq;
1084         }
1085
1086         ret = request_irq(IRQ_VEPU, vepu_isr, IRQF_SHARED, "vepu", (void *)&enc_dev);
1087         if (ret) {
1088                 pr_err("can't request vepu irq %d\n", IRQ_VEPU);
1089                 goto err_req_vepu_irq;
1090         }
1091
1092         ret = misc_register(&vpu_service_misc_device);
1093         if (ret) {
1094                 pr_err("misc_register failed\n");
1095                 goto err_register;
1096         }
1097
1098         platform_device_register(&vpu_service_device);
1099         platform_driver_probe(&vpu_service_driver, NULL);
1100         get_hw_info();
1101         del_timer(&service.timer);
1102         vpu_service_power_off();
1103         pr_info("init success\n");
1104
1105         return 0;
1106
1107 err_register:
1108         free_irq(IRQ_VEPU, (void *)&enc_dev);
1109 err_req_vepu_irq:
1110         free_irq(IRQ_VDPU, (void *)&dec_dev);
1111 err_req_vdpu_irq:
1112         pr_info("init failed\n");
1113 err_reserve_io:
1114         del_timer(&service.timer);
1115         vpu_service_power_off();
1116         vpu_service_release_io();
1117         vpu_put_clk();
1118         pr_info("init failed\n");
1119         return ret;
1120 }
1121
1122 static void __exit vpu_service_exit(void)
1123 {
1124         del_timer(&service.timer);
1125         vpu_service_power_off();
1126         platform_device_unregister(&vpu_service_device);
1127         platform_driver_unregister(&vpu_service_driver);
1128         misc_deregister(&vpu_service_misc_device);
1129         free_irq(IRQ_VEPU, (void *)&enc_dev);
1130         free_irq(IRQ_VDPU, (void *)&dec_dev);
1131         vpu_put_clk();
1132 }
1133
1134 module_init(vpu_service_init);
1135 module_exit(vpu_service_exit);
1136 MODULE_LICENSE("GPL");
1137
1138 #ifdef CONFIG_PROC_FS
1139 #include <linux/proc_fs.h>
1140 #include <linux/seq_file.h>
1141
1142 static int proc_vpu_service_show(struct seq_file *s, void *v)
1143 {
1144         unsigned int i, n;
1145         unsigned long flag;
1146         vpu_reg *reg, *reg_tmp;
1147         vpu_session *session, *session_tmp;
1148
1149         vpu_service_power_on();
1150         seq_printf(s, "\nENC Registers:\n");
1151         n = enc_dev.iosize >> 2;
1152         for (i = 0; i < n; i++) {
1153                 seq_printf(s, "\tswreg%d = %08X\n", i, readl(enc_dev.hwregs + i));
1154         }
1155         seq_printf(s, "\nDEC Registers:\n");
1156         n = dec_dev.iosize >> 2;
1157         for (i = 0; i < n; i++) {
1158                 seq_printf(s, "\tswreg%d = %08X\n", i, readl(dec_dev.hwregs + i));
1159         }
1160
1161         seq_printf(s, "\nvpu service status:\n");
1162         spin_lock_irqsave(&service.lock, flag);
1163         list_for_each_entry_safe(session, session_tmp, &service.session, list_session) {
1164                 seq_printf(s, "session pid %d type %d:\n", session->pid, session->type);
1165                 //seq_printf(s, "waiting reg set %d\n");
1166                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {
1167                         seq_printf(s, "waiting register set\n");
1168                 }
1169                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {
1170                         seq_printf(s, "running register set\n");
1171                 }
1172                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {
1173                         seq_printf(s, "done    register set\n");
1174                 }
1175         }
1176         spin_unlock_irqrestore(&service.lock, flag);
1177
1178         return 0;
1179 }
1180
1181 static int proc_vpu_service_open(struct inode *inode, struct file *file)
1182 {
1183         return single_open(file, proc_vpu_service_show, NULL);
1184 }
1185
1186 static const struct file_operations proc_vpu_service_fops = {
1187         .open           = proc_vpu_service_open,
1188         .read           = seq_read,
1189         .llseek         = seq_lseek,
1190         .release        = single_release,
1191 };
1192
1193 static int __init vpu_service_proc_init(void)
1194 {
1195         proc_create("vpu_service", 0, NULL, &proc_vpu_service_fops);
1196         return 0;
1197
1198 }
1199 late_initcall(vpu_service_proc_init);
1200 #endif /* CONFIG_PROC_FS */
1201