upload vcodec (vpu and hevc) service driver
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / vcodec_service.c
1 \r
2 /* arch/arm/mach-rk29/vpu.c\r
3  *\r
4  * Copyright (C) 2010 ROCKCHIP, Inc.\r
5  * author: chenhengming chm@rock-chips.com\r
6  *\r
7  * This software is licensed under the terms of the GNU General Public\r
8  * License version 2, as published by the Free Software Foundation, and\r
9  * may be copied, distributed, and modified under those terms.\r
10  *\r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  */\r
17 \r
18 #include <linux/clk.h>\r
19 #include <linux/delay.h>\r
20 #include <linux/init.h>\r
21 #include <linux/interrupt.h>\r
22 #include <linux/io.h>\r
23 #include <linux/kernel.h>\r
24 #include <linux/module.h>\r
25 #include <linux/fs.h>\r
26 #include <linux/ioport.h>\r
27 #include <linux/miscdevice.h>\r
28 #include <linux/mm.h>\r
29 #include <linux/poll.h>\r
30 #include <linux/platform_device.h>\r
31 #include <linux/sched.h>\r
32 #include <linux/slab.h>\r
33 #include <linux/wakelock.h>\r
34 #include <linux/cdev.h>\r
35 #include <linux/of.h>\r
36 \r
37 #include <asm/cacheflush.h>\r
38 #include <asm/uaccess.h>\r
39 \r
40 #ifdef CONFIG_DEBUG_FS\r
41 #include <linux/debugfs.h>\r
42 #endif\r
43 \r
44 #include "cru.h"\r
45 \r
46 #if defined(CONFIG_ARCH_RK319X)\r
47 #include <mach/grf.h>\r
48 #endif\r
49 \r
50 #include "vcodec_service.h"\r
51 #include "cpu.h"\r
52 \r
53 #define HEVC_TEST_ENABLE    0\r
54 #define HEVC_SIM_ENABLE         0\r
55 \r
56 typedef enum {\r
57         VPU_DEC_ID_9190         = 0x6731,\r
58         VPU_ID_8270             = 0x8270,\r
59         VPU_ID_4831             = 0x4831,\r
60     HEVC_ID         = 0x6867,\r
61 } VPU_HW_ID;\r
62 \r
63 typedef enum {\r
64         VPU_DEC_TYPE_9190       = 0,\r
65         VPU_ENC_TYPE_8270       = 0x100,\r
66         VPU_ENC_TYPE_4831       ,\r
67 } VPU_HW_TYPE_E;\r
68 \r
69 typedef enum VPU_FREQ {\r
70         VPU_FREQ_200M,\r
71         VPU_FREQ_266M,\r
72         VPU_FREQ_300M,\r
73         VPU_FREQ_400M,\r
74         VPU_FREQ_DEFAULT,\r
75         VPU_FREQ_BUT,\r
76 } VPU_FREQ;\r
77 \r
78 typedef struct {\r
79         VPU_HW_ID               hw_id;\r
80         unsigned long           hw_addr;\r
81         unsigned long           enc_offset;\r
82         unsigned long           enc_reg_num;\r
83         unsigned long           enc_io_size;\r
84         unsigned long           dec_offset;\r
85         unsigned long           dec_reg_num;\r
86         unsigned long           dec_io_size;\r
87 } VPU_HW_INFO_E;\r
88 \r
89 #define VPU_SERVICE_SHOW_TIME                   0\r
90 \r
91 #if VPU_SERVICE_SHOW_TIME\r
92 static struct timeval enc_start, enc_end;\r
93 static struct timeval dec_start, dec_end;\r
94 static struct timeval pp_start,  pp_end;\r
95 #endif\r
96 \r
97 #define MHZ                                     (1000*1000)\r
98 \r
99 #if 0\r
100 #if defined(CONFIG_ARCH_RK319X)\r
101 #define VCODEC_PHYS             RK319X_VCODEC_PHYS\r
102 #else\r
103 #define VCODEC_PHYS                             (0x10104000)\r
104 #endif\r
105 #endif\r
106 \r
107 #define REG_NUM_9190_DEC                        (60)\r
108 #define REG_NUM_9190_PP                         (41)\r
109 #define REG_NUM_9190_DEC_PP                     (REG_NUM_9190_DEC+REG_NUM_9190_PP)\r
110 \r
111 #define REG_NUM_DEC_PP                          (REG_NUM_9190_DEC+REG_NUM_9190_PP)\r
112 \r
113 #define REG_NUM_ENC_8270                        (96)\r
114 #define REG_SIZE_ENC_8270                       (0x200)\r
115 #define REG_NUM_ENC_4831                        (164)\r
116 #define REG_SIZE_ENC_4831                       (0x400)\r
117 \r
118 #define REG_NUM_HEVC_DEC            (68)\r
119 \r
120 #define SIZE_REG(reg)                           ((reg)*4)\r
121 \r
122 static VPU_HW_INFO_E vpu_hw_set[] = {\r
123         [0] = {\r
124                 .hw_id          = VPU_ID_8270,\r
125                 .hw_addr        = 0,\r
126                 .enc_offset     = 0x0,\r
127                 .enc_reg_num    = REG_NUM_ENC_8270,\r
128                 .enc_io_size    = REG_NUM_ENC_8270 * 4,\r
129                 .dec_offset     = REG_SIZE_ENC_8270,\r
130                 .dec_reg_num    = REG_NUM_9190_DEC_PP,\r
131                 .dec_io_size    = REG_NUM_9190_DEC_PP * 4,\r
132         },\r
133         [1] = {\r
134                 .hw_id          = VPU_ID_4831,\r
135                 .hw_addr        = 0,\r
136                 .enc_offset     = 0x0,\r
137                 .enc_reg_num    = REG_NUM_ENC_4831,\r
138                 .enc_io_size    = REG_NUM_ENC_4831 * 4,\r
139                 .dec_offset     = REG_SIZE_ENC_4831,\r
140                 .dec_reg_num    = REG_NUM_9190_DEC_PP,\r
141                 .dec_io_size    = REG_NUM_9190_DEC_PP * 4,\r
142         },\r
143     [2] = {\r
144         .hw_id      = HEVC_ID,\r
145         .hw_addr    = 0,\r
146         .dec_offset = 0x0,\r
147         .dec_reg_num    = REG_NUM_HEVC_DEC,\r
148         .dec_io_size    = REG_NUM_HEVC_DEC * 4,\r
149     },\r
150 };\r
151 \r
152 \r
153 #define DEC_INTERRUPT_REGISTER                  1\r
154 #define PP_INTERRUPT_REGISTER                   60\r
155 #define ENC_INTERRUPT_REGISTER                  1\r
156 \r
157 #define DEC_INTERRUPT_BIT                       0x100\r
158 #define DEC_BUFFER_EMPTY_BIT                    0x4000\r
159 #define PP_INTERRUPT_BIT                        0x100\r
160 #define ENC_INTERRUPT_BIT                       0x1\r
161 \r
162 #define HEVC_DEC_INT_RAW_BIT        0x200\r
163 #define HEVC_DEC_STR_ERROR_BIT      0x4000\r
164 #define HEVC_DEC_BUS_ERROR_BIT      0x2000\r
165 #define HEVC_DEC_BUFFER_EMPTY_BIT   0x10000\r
166 \r
167 #define VPU_REG_EN_ENC                          14\r
168 #define VPU_REG_ENC_GATE                        2\r
169 #define VPU_REG_ENC_GATE_BIT                    (1<<4)\r
170 \r
171 #define VPU_REG_EN_DEC                          1\r
172 #define VPU_REG_DEC_GATE                        2\r
173 #define VPU_REG_DEC_GATE_BIT                    (1<<10)\r
174 #define VPU_REG_EN_PP                           0\r
175 #define VPU_REG_PP_GATE                         1\r
176 #define VPU_REG_PP_GATE_BIT                     (1<<8)\r
177 #define VPU_REG_EN_DEC_PP                       1\r
178 #define VPU_REG_DEC_PP_GATE                     61\r
179 #define VPU_REG_DEC_PP_GATE_BIT                 (1<<8)\r
180 \r
181 /**\r
182  * struct for process session which connect to vpu\r
183  *\r
184  * @author ChenHengming (2011-5-3)\r
185  */\r
186 typedef struct vpu_session {\r
187         VPU_CLIENT_TYPE         type;\r
188         /* a linked list of data so we can access them for debugging */\r
189         struct list_head        list_session;\r
190         /* a linked list of register data waiting for process */\r
191         struct list_head        waiting;\r
192         /* a linked list of register data in processing */\r
193         struct list_head        running;\r
194         /* a linked list of register data processed */\r
195         struct list_head        done;\r
196         wait_queue_head_t       wait;\r
197         pid_t                   pid;\r
198         atomic_t                task_running;\r
199 } vpu_session;\r
200 \r
201 /**\r
202  * struct for process register set\r
203  *\r
204  * @author ChenHengming (2011-5-4)\r
205  */\r
206 typedef struct vpu_reg {\r
207         VPU_CLIENT_TYPE         type;\r
208         VPU_FREQ                freq;\r
209         vpu_session             *session;\r
210         struct list_head        session_link;           /* link to vpu service session */\r
211         struct list_head        status_link;            /* link to register set list */\r
212         unsigned long           size;\r
213         unsigned long           *reg;\r
214 } vpu_reg;\r
215 \r
216 typedef struct vpu_device {\r
217         atomic_t                irq_count_codec;\r
218         atomic_t                irq_count_pp;\r
219         unsigned long           iobaseaddr;\r
220         unsigned int            iosize;\r
221         volatile u32            *hwregs;\r
222 } vpu_device;\r
223 \r
224 typedef struct vpu_service_info {\r
225         struct wake_lock        wake_lock;\r
226         struct delayed_work     power_off_work;\r
227         struct mutex            lock;\r
228         struct list_head        waiting;                /* link to link_reg in struct vpu_reg */\r
229         struct list_head        running;                /* link to link_reg in struct vpu_reg */\r
230         struct list_head        done;                   /* link to link_reg in struct vpu_reg */\r
231         struct list_head        session;                /* link to list_session in struct vpu_session */\r
232         atomic_t                total_running;\r
233         bool                    enabled;\r
234         vpu_reg                 *reg_codec;\r
235         vpu_reg                 *reg_pproc;\r
236         vpu_reg                 *reg_resev;\r
237         VPUHwDecConfig_t        dec_config;\r
238         VPUHwEncConfig_t        enc_config;\r
239         VPU_HW_INFO_E           *hw_info;\r
240         unsigned long           reg_size;\r
241         bool                    auto_freq;\r
242         bool                    bug_dec_addr;\r
243         atomic_t                freq_status;\r
244 \r
245     struct clk *aclk_vcodec;\r
246     struct clk *hclk_vcodec;\r
247 \r
248     int irq_dec;\r
249     int irq_enc;\r
250 \r
251     vpu_device enc_dev;\r
252     vpu_device dec_dev;\r
253 \r
254     struct device   *dev;\r
255 \r
256     struct cdev     cdev;\r
257     dev_t           dev_t;\r
258     struct class    *cls;\r
259     struct device   *child_dev;\r
260 \r
261     struct dentry   *debugfs_dir;\r
262     struct dentry   *debugfs_file_regs;\r
263 \r
264     u32 irq_status;\r
265 \r
266     struct delayed_work simulate_work;\r
267 } vpu_service_info;\r
268 \r
269 typedef struct vpu_request\r
270 {\r
271         unsigned long   *req;\r
272         unsigned long   size;\r
273 } vpu_request;\r
274 \r
275 /// global variable\r
276 //static struct clk *pd_video;\r
277 static struct dentry *parent; // debugfs root directory for all device (vpu, hevc).\r
278 \r
279 #ifdef CONFIG_DEBUG_FS\r
280 static int vcodec_debugfs_init(void);\r
281 static void vcodec_debugfs_exit(void);\r
282 static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent);\r
283 static int debug_vcodec_open(struct inode *inode, struct file *file);\r
284 \r
285 static const struct file_operations debug_vcodec_fops = {\r
286         .open = debug_vcodec_open,\r
287         .read = seq_read,\r
288         .llseek = seq_lseek,\r
289         .release = single_release,\r
290 };\r
291 #endif\r
292 \r
293 #define VPU_POWER_OFF_DELAY             4*HZ /* 4s */\r
294 #define VPU_TIMEOUT_DELAY               2*HZ /* 2s */\r
295 \r
296 #define VPU_SIMULATE_DELAY      msecs_to_jiffies(5)\r
297 \r
298 static void vpu_get_clk(struct vpu_service_info *pservice)\r
299 {\r
300         /*pd_video      = clk_get(NULL, "pd_video");\r
301         if (IS_ERR(pd_video)) {\r
302                 pr_err("failed on clk_get pd_video\n");\r
303         }*/\r
304         pservice->aclk_vcodec   = devm_clk_get(pservice->dev, "aclk_vcodec");\r
305         if (IS_ERR(pservice->aclk_vcodec)) {\r
306                 dev_err(pservice->dev, "failed on clk_get aclk_vcodec\n");\r
307         }\r
308         pservice->hclk_vcodec   = devm_clk_get(pservice->dev, "hclk_vcodec");\r
309         if (IS_ERR(pservice->hclk_vcodec)) {\r
310                 dev_err(pservice->dev, "failed on clk_get hclk_vcodec\n");\r
311         }\r
312 }\r
313 \r
314 static void vpu_put_clk(struct vpu_service_info *pservice)\r
315 {\r
316     //clk_put(pd_video);\r
317 \r
318     if (pservice->aclk_vcodec) {\r
319         devm_clk_put(pservice->dev, pservice->aclk_vcodec);\r
320     }\r
321 \r
322     if (pservice->hclk_vcodec) {\r
323         devm_clk_put(pservice->dev, pservice->hclk_vcodec);\r
324     }\r
325 }\r
326 \r
327 static void vpu_reset(struct vpu_service_info *pservice)\r
328 {\r
329 #if defined(CONFIG_ARCH_RK29)\r
330         clk_disable(aclk_ddr_vepu);\r
331         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);\r
332         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);\r
333         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);\r
334         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);\r
335         mdelay(10);\r
336         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);\r
337         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);\r
338         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);\r
339         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);\r
340         clk_enable(aclk_ddr_vepu);\r
341 #elif defined(CONFIG_ARCH_RK30)\r
342         pmu_set_idle_request(IDLE_REQ_VIDEO, true);\r
343         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true);\r
344         cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, true);\r
345         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true);\r
346         cru_set_soft_reset(SOFT_RST_VCODEC_AXI, true);\r
347         mdelay(1);\r
348         cru_set_soft_reset(SOFT_RST_VCODEC_AXI, false);\r
349         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false);\r
350         cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, false);\r
351         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);\r
352         pmu_set_idle_request(IDLE_REQ_VIDEO, false);\r
353 #endif\r
354         pservice->reg_codec = NULL;\r
355         pservice->reg_pproc = NULL;\r
356         pservice->reg_resev = NULL;\r
357 }\r
358 \r
359 static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg);\r
360 static void vpu_service_session_clear(struct vpu_service_info *pservice, vpu_session *session)\r
361 {\r
362         vpu_reg *reg, *n;\r
363         list_for_each_entry_safe(reg, n, &session->waiting, session_link) {\r
364                 reg_deinit(pservice, reg);\r
365         }\r
366         list_for_each_entry_safe(reg, n, &session->running, session_link) {\r
367                 reg_deinit(pservice, reg);\r
368         }\r
369         list_for_each_entry_safe(reg, n, &session->done, session_link) {\r
370                 reg_deinit(pservice, reg);\r
371         }\r
372 }\r
373 \r
374 static void vpu_service_dump(struct vpu_service_info *pservice)\r
375 {\r
376         int running;\r
377         vpu_reg *reg, *reg_tmp;\r
378         vpu_session *session, *session_tmp;\r
379 \r
380         running = atomic_read(&pservice->total_running);\r
381         printk("total_running %d\n", running);\r
382 \r
383         printk("reg_codec 0x%.8x\n", (unsigned int)pservice->reg_codec);\r
384         printk("reg_pproc 0x%.8x\n", (unsigned int)pservice->reg_pproc);\r
385         printk("reg_resev 0x%.8x\n", (unsigned int)pservice->reg_resev);\r
386 \r
387         list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) {\r
388                 printk("session pid %d type %d:\n", session->pid, session->type);\r
389                 running = atomic_read(&session->task_running);\r
390                 printk("task_running %d\n", running);\r
391                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {\r
392                         printk("waiting register set 0x%.8x\n", (unsigned int)reg);\r
393                 }\r
394                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {\r
395                         printk("running register set 0x%.8x\n", (unsigned int)reg);\r
396                 }\r
397                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {\r
398                         printk("done    register set 0x%.8x\n", (unsigned int)reg);\r
399                 }\r
400         }\r
401 }\r
402 \r
403 static void vpu_service_power_off(struct vpu_service_info *pservice)\r
404 {\r
405         int total_running;\r
406         if (!pservice->enabled) {\r
407                 return;\r
408         }\r
409 \r
410         pservice->enabled = false;\r
411         total_running = atomic_read(&pservice->total_running);\r
412         if (total_running) {\r
413                 pr_alert("alert: power off when %d task running!!\n", total_running);\r
414                 mdelay(50);\r
415                 pr_alert("alert: delay 50 ms for running task\n");\r
416                 vpu_service_dump(pservice);\r
417         }\r
418 \r
419         printk("vpu: power off...");\r
420 #ifdef CONFIG_ARCH_RK29\r
421         pmu_set_power_domain(PD_VCODEC, false);\r
422 #else\r
423         //clk_disable(pd_video);\r
424 #endif\r
425         udelay(10);\r
426         //clk_disable(hclk_cpu_vcodec);\r
427         //clk_disable(aclk_ddr_vepu);\r
428 #if 0\r
429         clk_disable_unprepare(pservice->hclk_vcodec);\r
430         clk_disable_unprepare(pservice->aclk_vcodec);\r
431 #endif\r
432         wake_unlock(&pservice->wake_lock);\r
433         printk("done\n");\r
434 }\r
435 \r
436 static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice)\r
437 {\r
438         queue_delayed_work(system_nrt_wq, &pservice->power_off_work, VPU_POWER_OFF_DELAY);\r
439 }\r
440 \r
441 static void vpu_power_off_work(struct work_struct *work_s)\r
442 {\r
443     struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work);\r
444     struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, power_off_work);\r
445 \r
446         if (mutex_trylock(&pservice->lock)) {\r
447                 vpu_service_power_off(pservice);\r
448                 mutex_unlock(&pservice->lock);\r
449         } else {\r
450                 /* Come back later if the device is busy... */\r
451                 vpu_queue_power_off_work(pservice);\r
452         }\r
453 }\r
454 \r
455 static void vpu_service_power_on(struct vpu_service_info *pservice)\r
456 {\r
457         static ktime_t last;\r
458         ktime_t now = ktime_get();\r
459         if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {\r
460                 cancel_delayed_work_sync(&pservice->power_off_work);\r
461                 vpu_queue_power_off_work(pservice);\r
462                 last = now;\r
463         }\r
464         if (pservice->enabled)\r
465                 return ;\r
466 \r
467         pservice->enabled = true;\r
468         printk("vpu: power on\n");\r
469 \r
470 #if 0\r
471     clk_prepare_enable(pservice->aclk_vcodec);\r
472         clk_prepare_enable(pservice->hclk_vcodec);\r
473 #endif\r
474         //clk_prepare_enable(hclk_cpu_vcodec);\r
475 #if defined(CONFIG_ARCH_RK319X)\r
476     /// select aclk_vepu as vcodec clock source. \r
477     #define BIT_VCODEC_SEL  (1<<7)\r
478     writel_relaxed(readl_relaxed(RK319X_GRF_BASE + GRF_SOC_CON1) | (BIT_VCODEC_SEL) | (BIT_VCODEC_SEL << 16), RK319X_GRF_BASE + GRF_SOC_CON1);\r
479 #endif\r
480         udelay(10);\r
481 #ifdef CONFIG_ARCH_RK29\r
482         pmu_set_power_domain(PD_VCODEC, true);\r
483 #else\r
484         //clk_enable(pd_video);\r
485 #endif\r
486         udelay(10);\r
487         //clk_enable(aclk_ddr_vepu);\r
488         wake_lock(&pservice->wake_lock);\r
489 }\r
490 \r
491 static inline bool reg_check_rmvb_wmv(vpu_reg *reg)\r
492 {\r
493         unsigned long type = (reg->reg[3] & 0xF0000000) >> 28;\r
494         return ((type == 8) || (type == 4));\r
495 }\r
496 \r
497 static inline bool reg_check_interlace(vpu_reg *reg)\r
498 {\r
499         unsigned long type = (reg->reg[3] & (1 << 23));\r
500         return (type > 0);\r
501 }\r
502 \r
503 static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session, void __user *src, unsigned long size)\r
504 {\r
505         vpu_reg *reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);\r
506         if (NULL == reg) {\r
507                 pr_err("error: kmalloc fail in reg_init\n");\r
508                 return NULL;\r
509         }\r
510 \r
511         if (size > pservice->reg_size) {\r
512                 printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
513                 size = pservice->reg_size;\r
514         }\r
515         reg->session = session;\r
516         reg->type = session->type;\r
517         reg->size = size;\r
518         reg->freq = VPU_FREQ_DEFAULT;\r
519         reg->reg = (unsigned long *)&reg[1];\r
520         INIT_LIST_HEAD(&reg->session_link);\r
521         INIT_LIST_HEAD(&reg->status_link);\r
522 \r
523         if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {\r
524                 pr_err("error: copy_from_user failed in reg_init\n");\r
525                 kfree(reg);\r
526                 return NULL;\r
527         }\r
528 \r
529         mutex_lock(&pservice->lock);\r
530         list_add_tail(&reg->status_link, &pservice->waiting);\r
531         list_add_tail(&reg->session_link, &session->waiting);\r
532         mutex_unlock(&pservice->lock);\r
533 \r
534         if (pservice->auto_freq) {\r
535                 if (!soc_is_rk2928g()) {\r
536                         if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {\r
537                                 if (reg_check_rmvb_wmv(reg)) {\r
538                                         reg->freq = VPU_FREQ_200M;\r
539                                 } else {\r
540                                         if (reg_check_interlace(reg)) {\r
541                                                 reg->freq = VPU_FREQ_400M;\r
542                                         }\r
543                                 }\r
544                         }\r
545                         if (reg->type == VPU_PP) {\r
546                                 reg->freq = VPU_FREQ_400M;\r
547                         }\r
548                 }\r
549         }\r
550 \r
551         return reg;\r
552 }\r
553 \r
554 static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg)\r
555 {\r
556         list_del_init(&reg->session_link);\r
557         list_del_init(&reg->status_link);\r
558         if (reg == pservice->reg_codec) pservice->reg_codec = NULL;\r
559         if (reg == pservice->reg_pproc) pservice->reg_pproc = NULL;\r
560         kfree(reg);\r
561 }\r
562 \r
563 static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg)\r
564 {\r
565         list_del_init(&reg->status_link);\r
566         list_add_tail(&reg->status_link, &pservice->running);\r
567 \r
568         list_del_init(&reg->session_link);\r
569         list_add_tail(&reg->session_link, &reg->session->running);\r
570 }\r
571 \r
572 static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count)\r
573 {\r
574         int i;\r
575         u32 *dst = (u32 *)&reg->reg[0];\r
576         for (i = 0; i < count; i++)\r
577                 *dst++ = *src++;\r
578 }\r
579 \r
580 static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg)\r
581 {\r
582     int irq_reg = -1;\r
583         list_del_init(&reg->status_link);\r
584         list_add_tail(&reg->status_link, &pservice->done);\r
585 \r
586         list_del_init(&reg->session_link);\r
587         list_add_tail(&reg->session_link, &reg->session->done);\r
588 \r
589         switch (reg->type) {\r
590         case VPU_ENC : {\r
591                 pservice->reg_codec = NULL;\r
592                 reg_copy_from_hw(reg, pservice->enc_dev.hwregs, pservice->hw_info->enc_reg_num);\r
593         irq_reg = ENC_INTERRUPT_REGISTER;\r
594                 break;\r
595         }\r
596         case VPU_DEC : {\r
597                 pservice->reg_codec = NULL;\r
598                 reg_copy_from_hw(reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC);\r
599         irq_reg = DEC_INTERRUPT_REGISTER;\r
600                 break;\r
601         }\r
602         case VPU_PP : {\r
603                 pservice->reg_pproc = NULL;\r
604                 reg_copy_from_hw(reg, pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP);\r
605                 pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;\r
606                 break;\r
607         }\r
608         case VPU_DEC_PP : {\r
609                 pservice->reg_codec = NULL;\r
610                 pservice->reg_pproc = NULL;\r
611                 reg_copy_from_hw(reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC_PP);\r
612                 pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;\r
613                 break;\r
614         }\r
615         default : {\r
616                 pr_err("error: copy reg from hw with unknown type %d\n", reg->type);\r
617                 break;\r
618         }\r
619         }\r
620 \r
621     if (irq_reg != -1) {\r
622         reg->reg[irq_reg] = pservice->irq_status;\r
623     }\r
624 \r
625         atomic_sub(1, &reg->session->task_running);\r
626         atomic_sub(1, &pservice->total_running);\r
627         wake_up(&reg->session->wait);\r
628 }\r
629 \r
630 static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg)\r
631 {\r
632         VPU_FREQ curr = atomic_read(&pservice->freq_status);\r
633         if (curr == reg->freq) {\r
634                 return ;\r
635         }\r
636         atomic_set(&pservice->freq_status, reg->freq);\r
637         switch (reg->freq) {\r
638         case VPU_FREQ_200M : {\r
639                 clk_set_rate(pservice->aclk_vcodec, 200*MHZ);\r
640                 //printk("default: 200M\n");\r
641         } break;\r
642         case VPU_FREQ_266M : {\r
643                 clk_set_rate(pservice->aclk_vcodec, 266*MHZ);\r
644                 //printk("default: 266M\n");\r
645         } break;\r
646         case VPU_FREQ_300M : {\r
647                 clk_set_rate(pservice->aclk_vcodec, 300*MHZ);\r
648                 //printk("default: 300M\n");\r
649         } break;\r
650         case VPU_FREQ_400M : {\r
651                 clk_set_rate(pservice->aclk_vcodec, 400*MHZ);\r
652                 //printk("default: 400M\n");\r
653         } break;\r
654         default : {\r
655                 if (soc_is_rk2928g()) {\r
656                         clk_set_rate(pservice->aclk_vcodec, 400*MHZ);\r
657                 } else {\r
658                         clk_set_rate(pservice->aclk_vcodec, 300*MHZ);\r
659                 }\r
660                 //printk("default: 300M\n");\r
661         } break;\r
662         }\r
663 }\r
664 \r
665 #if HEVC_SIM_ENABLE\r
666 static void simulate_start(struct vpu_service_info *pservice);\r
667 #endif\r
668 static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg)\r
669 {\r
670         int i;\r
671         u32 *src = (u32 *)&reg->reg[0];\r
672         atomic_add(1, &pservice->total_running);\r
673         atomic_add(1, &reg->session->task_running);\r
674         if (pservice->auto_freq) {\r
675                 vpu_service_set_freq(pservice, reg);\r
676         }\r
677         switch (reg->type) {\r
678         case VPU_ENC : {\r
679                 int enc_count = pservice->hw_info->enc_reg_num;\r
680                 u32 *dst = (u32 *)pservice->enc_dev.hwregs;\r
681 #if 0\r
682                 if (pservice->bug_dec_addr) {\r
683 #if !defined(CONFIG_ARCH_RK319X)\r
684                         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true);\r
685 #endif\r
686                         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true);\r
687                         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false);\r
688 #if !defined(CONFIG_ARCH_RK319X)\r
689                         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);\r
690 #endif\r
691                 }\r
692 #endif\r
693                 pservice->reg_codec = reg;\r
694 \r
695                 dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;\r
696 \r
697                 for (i = 0; i < VPU_REG_EN_ENC; i++)\r
698                         dst[i] = src[i];\r
699 \r
700                 for (i = VPU_REG_EN_ENC + 1; i < enc_count; i++)\r
701                         dst[i] = src[i];\r
702 \r
703                 dsb();\r
704 \r
705                 dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;\r
706                 dst[VPU_REG_EN_ENC]   = src[VPU_REG_EN_ENC];\r
707 \r
708 #if VPU_SERVICE_SHOW_TIME\r
709                 do_gettimeofday(&enc_start);\r
710 #endif\r
711 \r
712         } break;\r
713         case VPU_DEC : {\r
714                 u32 *dst = (u32 *)pservice->dec_dev.hwregs;\r
715                 pservice->reg_codec = reg;\r
716 \r
717                 for (i = REG_NUM_9190_DEC - 1; i > VPU_REG_DEC_GATE; i--)\r
718                         dst[i] = src[i];\r
719 \r
720                 dsb();\r
721 \r
722                 dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;\r
723                 dst[VPU_REG_EN_DEC]   = src[VPU_REG_EN_DEC];\r
724 \r
725 #if VPU_SERVICE_SHOW_TIME\r
726                 do_gettimeofday(&dec_start);\r
727 #endif\r
728 \r
729         } break;\r
730         case VPU_PP : {\r
731                 u32 *dst = (u32 *)pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER;\r
732                 pservice->reg_pproc = reg;\r
733 \r
734                 dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;\r
735 \r
736                 for (i = VPU_REG_PP_GATE + 1; i < REG_NUM_9190_PP; i++)\r
737                         dst[i] = src[i];\r
738 \r
739                 dsb();\r
740 \r
741                 dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];\r
742 \r
743 #if VPU_SERVICE_SHOW_TIME\r
744                 do_gettimeofday(&pp_start);\r
745 #endif\r
746 \r
747         } break;\r
748         case VPU_DEC_PP : {\r
749                 u32 *dst = (u32 *)pservice->dec_dev.hwregs;\r
750                 pservice->reg_codec = reg;\r
751                 pservice->reg_pproc = reg;\r
752 \r
753                 for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_9190_DEC_PP; i++)\r
754                         dst[i] = src[i];\r
755 \r
756                 dst[VPU_REG_EN_DEC_PP]   = src[VPU_REG_EN_DEC_PP] | 0x2;\r
757                 dsb();\r
758 \r
759                 dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;\r
760                 dst[VPU_REG_DEC_GATE]    = src[VPU_REG_DEC_GATE]    | VPU_REG_DEC_GATE_BIT;\r
761                 dst[VPU_REG_EN_DEC]      = src[VPU_REG_EN_DEC];\r
762 \r
763 #if VPU_SERVICE_SHOW_TIME\r
764                 do_gettimeofday(&dec_start);\r
765 #endif\r
766 \r
767         } break;\r
768         default : {\r
769                 pr_err("error: unsupport session type %d", reg->type);\r
770                 atomic_sub(1, &pservice->total_running);\r
771                 atomic_sub(1, &reg->session->task_running);\r
772                 break;\r
773         }\r
774         }\r
775 \r
776 #if HEVC_SIM_ENABLE\r
777     if (pservice->hw_info->hw_id == HEVC_ID) {\r
778         simulate_start(pservice);\r
779     }\r
780 #endif\r
781 }\r
782 \r
783 static void try_set_reg(struct vpu_service_info *pservice)\r
784 {\r
785         // first get reg from reg list\r
786         if (!list_empty(&pservice->waiting)) {\r
787                 int can_set = 0;\r
788                 vpu_reg *reg = list_entry(pservice->waiting.next, vpu_reg, status_link);\r
789 \r
790                 vpu_service_power_on(pservice);\r
791 \r
792                 switch (reg->type) {\r
793                 case VPU_ENC : {\r
794                         if ((NULL == pservice->reg_codec) &&  (NULL == pservice->reg_pproc))\r
795                                 can_set = 1;\r
796                 } break;\r
797                 case VPU_DEC : {\r
798                         if (NULL == pservice->reg_codec)\r
799                                 can_set = 1;\r
800                         if (pservice->auto_freq && (NULL != pservice->reg_pproc)) {\r
801                                 can_set = 0;\r
802                         }\r
803                 } break;\r
804                 case VPU_PP : {\r
805                         if (NULL == pservice->reg_codec) {\r
806                                 if (NULL == pservice->reg_pproc)\r
807                                         can_set = 1;\r
808                         } else {\r
809                                 if ((VPU_DEC == pservice->reg_codec->type) && (NULL == pservice->reg_pproc))\r
810                                         can_set = 1;\r
811                                 // can not charge frequency when vpu is working\r
812                                 if (pservice->auto_freq) {\r
813                                         can_set = 0;\r
814                                 }\r
815                         }\r
816                 } break;\r
817                 case VPU_DEC_PP : {\r
818                         if ((NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc))\r
819                                 can_set = 1;\r
820                         } break;\r
821                 default : {\r
822                         printk("undefined reg type %d\n", reg->type);\r
823                 } break;\r
824                 }\r
825                 if (can_set) {\r
826                         reg_from_wait_to_run(pservice, reg);\r
827                         reg_copy_to_hw(pservice, reg);\r
828                 }\r
829         }\r
830 }\r
831 \r
832 static int return_reg(struct vpu_service_info *pservice, vpu_reg *reg, u32 __user *dst)\r
833 {\r
834         int ret = 0;\r
835         switch (reg->type) {\r
836         case VPU_ENC : {\r
837                 if (copy_to_user(dst, &reg->reg[0], pservice->hw_info->enc_io_size))\r
838                         ret = -EFAULT;\r
839                 break;\r
840         }\r
841         case VPU_DEC : {\r
842                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_DEC)))\r
843                         ret = -EFAULT;\r
844                 break;\r
845         }\r
846         case VPU_PP : {\r
847                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_PP)))\r
848                         ret = -EFAULT;\r
849                 break;\r
850         }\r
851         case VPU_DEC_PP : {\r
852                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_DEC_PP)))\r
853                         ret = -EFAULT;\r
854                 break;\r
855         }\r
856         default : {\r
857                 ret = -EFAULT;\r
858                 pr_err("error: copy reg to user with unknown type %d\n", reg->type);\r
859                 break;\r
860         }\r
861         }\r
862         reg_deinit(pservice, reg);\r
863         return ret;\r
864 }\r
865 \r
866 static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
867 {\r
868     struct vpu_service_info *pservice = container_of(filp->f_dentry->d_inode->i_cdev, struct vpu_service_info, cdev);\r
869         vpu_session *session = (vpu_session *)filp->private_data;\r
870         if (NULL == session) {\r
871                 return -EINVAL;\r
872         }\r
873 \r
874         switch (cmd) {\r
875         case VPU_IOC_SET_CLIENT_TYPE : {\r
876                 session->type = (VPU_CLIENT_TYPE)arg;\r
877                 break;\r
878         }\r
879         case VPU_IOC_GET_HW_FUSE_STATUS : {\r
880                 vpu_request req;\r
881                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
882                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n");\r
883                         return -EFAULT;\r
884                 } else {\r
885                         if (VPU_ENC != session->type) {\r
886                                 if (copy_to_user((void __user *)req.req, &pservice->dec_config, sizeof(VPUHwDecConfig_t))) {\r
887                                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);\r
888                                         return -EFAULT;\r
889                                 }\r
890                         } else {\r
891                                 if (copy_to_user((void __user *)req.req, &pservice->enc_config, sizeof(VPUHwEncConfig_t))) {\r
892                                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);\r
893                                         return -EFAULT;\r
894                                 }\r
895                         }\r
896                 }\r
897 \r
898                 break;\r
899         }\r
900         case VPU_IOC_SET_REG : {\r
901                 vpu_request req;\r
902                 vpu_reg *reg;\r
903                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
904                         pr_err("error: VPU_IOC_SET_REG copy_from_user failed\n");\r
905                         return -EFAULT;\r
906                 }\r
907                 reg = reg_init(pservice, session, (void __user *)req.req, req.size);\r
908                 if (NULL == reg) {\r
909                         return -EFAULT;\r
910                 } else {\r
911                         mutex_lock(&pservice->lock);\r
912                         try_set_reg(pservice);\r
913                         mutex_unlock(&pservice->lock);\r
914                 }\r
915 \r
916                 break;\r
917         }\r
918         case VPU_IOC_GET_REG : {\r
919                 vpu_request req;\r
920                 vpu_reg *reg;\r
921                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
922                         pr_err("error: VPU_IOC_GET_REG copy_from_user failed\n");\r
923                         return -EFAULT;\r
924                 } else {\r
925                         int ret = wait_event_timeout(session->wait, !list_empty(&session->done), VPU_TIMEOUT_DELAY);\r
926                         if (!list_empty(&session->done)) {\r
927                                 if (ret < 0) {\r
928                                         pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret);\r
929                                 }\r
930                                 ret = 0;\r
931                         } else {\r
932                                 if (unlikely(ret < 0)) {\r
933                                         pr_err("error: pid %d wait task ret %d\n", session->pid, ret);\r
934                                 } else if (0 == ret) {\r
935                                         pr_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));\r
936                                         ret = -ETIMEDOUT;\r
937                                 }\r
938                         }\r
939                         if (ret < 0) {\r
940                                 int task_running = atomic_read(&session->task_running);\r
941                                 mutex_lock(&pservice->lock);\r
942                                 vpu_service_dump(pservice);\r
943                                 if (task_running) {\r
944                                         atomic_set(&session->task_running, 0);\r
945                                         atomic_sub(task_running, &pservice->total_running);\r
946                                         printk("%d task is running but not return, reset hardware...", task_running);\r
947                                         vpu_reset(pservice);\r
948                                         printk("done\n");\r
949                                 }\r
950                                 vpu_service_session_clear(pservice, session);\r
951                                 mutex_unlock(&pservice->lock);\r
952                                 return ret;\r
953                         }\r
954                 }\r
955                 mutex_lock(&pservice->lock);\r
956                 reg = list_entry(session->done.next, vpu_reg, session_link);\r
957                 return_reg(pservice, reg, (u32 __user *)req.req);\r
958                 mutex_unlock(&pservice->lock);\r
959                 break;\r
960         }\r
961         default : {\r
962                 pr_err("error: unknow vpu service ioctl cmd %x\n", cmd);\r
963                 break;\r
964         }\r
965         }\r
966 \r
967         return 0;\r
968 }\r
969 \r
970 static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr)\r
971 {\r
972         int ret = -EINVAL, i = 0;\r
973         volatile u32 *tmp = (volatile u32 *)ioremap_nocache(hw_addr, 0x4);\r
974         u32 enc_id = *tmp;\r
975 \r
976 #if 0\r
977     /// temporary, hevc driver test.\r
978     if (strncmp(dev_name(p->dev), "hevc_service", strlen("hevc_service")) == 0) {\r
979         p->hw_info = &vpu_hw_set[2];\r
980         return 0;\r
981     }\r
982 #endif\r
983 \r
984         enc_id = (enc_id >> 16) & 0xFFFF;\r
985         pr_info("checking hw id %x\n", enc_id);\r
986     p->hw_info = NULL;\r
987         for (i = 0; i < ARRAY_SIZE(vpu_hw_set); i++) {\r
988                 if (enc_id == vpu_hw_set[i].hw_id) {\r
989                         p->hw_info = &vpu_hw_set[i];\r
990                         ret = 0;\r
991                         break;\r
992                 }\r
993         }\r
994         iounmap((void *)tmp);\r
995         return ret;\r
996 }\r
997 \r
998 static int vpu_service_open(struct inode *inode, struct file *filp)\r
999 {\r
1000     struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev);\r
1001         vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL);\r
1002         if (NULL == session) {\r
1003                 pr_err("error: unable to allocate memory for vpu_session.");\r
1004                 return -ENOMEM;\r
1005         }\r
1006 \r
1007         session->type   = VPU_TYPE_BUTT;\r
1008         session->pid    = current->pid;\r
1009         INIT_LIST_HEAD(&session->waiting);\r
1010         INIT_LIST_HEAD(&session->running);\r
1011         INIT_LIST_HEAD(&session->done);\r
1012         INIT_LIST_HEAD(&session->list_session);\r
1013         init_waitqueue_head(&session->wait);\r
1014         atomic_set(&session->task_running, 0);\r
1015         mutex_lock(&pservice->lock);\r
1016         list_add_tail(&session->list_session, &pservice->session);\r
1017         filp->private_data = (void *)session;\r
1018         mutex_unlock(&pservice->lock);\r
1019 \r
1020         pr_debug("dev opened\n");\r
1021         return nonseekable_open(inode, filp);\r
1022 }\r
1023 \r
1024 static int vpu_service_release(struct inode *inode, struct file *filp)\r
1025 {\r
1026     struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev);\r
1027         int task_running;\r
1028         vpu_session *session = (vpu_session *)filp->private_data;\r
1029         if (NULL == session)\r
1030                 return -EINVAL;\r
1031 \r
1032         task_running = atomic_read(&session->task_running);\r
1033         if (task_running) {\r
1034                 pr_err("error: vpu_service session %d still has %d task running when closing\n", session->pid, task_running);\r
1035                 msleep(50);\r
1036         }\r
1037         wake_up(&session->wait);\r
1038 \r
1039         mutex_lock(&pservice->lock);\r
1040         /* remove this filp from the asynchronusly notified filp's */\r
1041         list_del_init(&session->list_session);\r
1042         vpu_service_session_clear(pservice, session);\r
1043         kfree(session);\r
1044         filp->private_data = NULL;\r
1045         mutex_unlock(&pservice->lock);\r
1046 \r
1047     pr_debug("dev closed\n");\r
1048         return 0;\r
1049 }\r
1050 \r
1051 static const struct file_operations vpu_service_fops = {\r
1052         .unlocked_ioctl = vpu_service_ioctl,\r
1053         .open           = vpu_service_open,\r
1054         .release        = vpu_service_release,\r
1055         //.fasync       = vpu_service_fasync,\r
1056 };\r
1057 \r
1058 static irqreturn_t vdpu_irq(int irq, void *dev_id);\r
1059 static irqreturn_t vdpu_isr(int irq, void *dev_id);\r
1060 static irqreturn_t vepu_irq(int irq, void *dev_id);\r
1061 static irqreturn_t vepu_isr(int irq, void *dev_id);\r
1062 static void get_hw_info(struct vpu_service_info *pservice);\r
1063 \r
1064 #if HEVC_SIM_ENABLE\r
1065 static void simulate_work(struct work_struct *work_s)\r
1066 {\r
1067     struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work);\r
1068     struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, simulate_work);\r
1069     vpu_device *dev = &pservice->dec_dev;\r
1070 \r
1071     if (!list_empty(&pservice->running)) {\r
1072         atomic_add(1, &dev->irq_count_codec);\r
1073         vdpu_isr(0, (void*)pservice);\r
1074     } else {\r
1075         //simulate_start(pservice);\r
1076         pr_err("empty running queue\n");\r
1077     }\r
1078 }\r
1079 \r
1080 static void simulate_init(struct vpu_service_info *pservice)\r
1081 {\r
1082     INIT_DELAYED_WORK(&pservice->simulate_work, simulate_work);\r
1083 }\r
1084 \r
1085 static void simulate_start(struct vpu_service_info *pservice)\r
1086 {\r
1087     cancel_delayed_work_sync(&pservice->power_off_work);\r
1088     queue_delayed_work(system_nrt_wq, &pservice->simulate_work, VPU_SIMULATE_DELAY);\r
1089 }\r
1090 #endif\r
1091 \r
1092 #if HEVC_TEST_ENABLE\r
1093 static int hevc_test_case0(vpu_service_info *pservice);\r
1094 #endif\r
1095 static int vcodec_probe(struct platform_device *pdev)\r
1096 {\r
1097     int ret = 0;\r
1098     struct resource *res = NULL;\r
1099     struct device *dev = &pdev->dev;\r
1100     void __iomem *regs = NULL;\r
1101     struct device_node *np = pdev->dev.of_node;\r
1102     struct vpu_service_info *pservice = devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL);\r
1103     char *prop = (char*)dev_name(dev);\r
1104 \r
1105     pr_info("probe device %s\n", dev_name(dev));\r
1106 \r
1107     of_property_read_string(np, "name", (const char**)&prop);\r
1108     dev_set_name(dev, prop);\r
1109 \r
1110     wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu");\r
1111     INIT_LIST_HEAD(&pservice->waiting);\r
1112     INIT_LIST_HEAD(&pservice->running);\r
1113     INIT_LIST_HEAD(&pservice->done);\r
1114     INIT_LIST_HEAD(&pservice->session);\r
1115     mutex_init(&pservice->lock);\r
1116     pservice->reg_codec = NULL;\r
1117     pservice->reg_pproc = NULL;\r
1118     atomic_set(&pservice->total_running, 0);\r
1119     pservice->enabled = false;\r
1120 \r
1121     pservice->dev = dev;\r
1122 \r
1123     vpu_get_clk(pservice);\r
1124 \r
1125     INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);\r
1126 \r
1127     vpu_service_power_on(pservice);\r
1128 \r
1129     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
1130 \r
1131     regs = devm_ioremap_resource(pservice->dev, res);\r
1132     if (IS_ERR(regs)) {\r
1133         ret = PTR_ERR(regs);\r
1134         goto err;\r
1135     }\r
1136 \r
1137     ret = vpu_service_check_hw(pservice, res->start);\r
1138     if (ret < 0) {\r
1139         pr_err("error: hw info check faild\n");\r
1140         goto err;\r
1141     }\r
1142 \r
1143     /// define regs address.\r
1144     pservice->dec_dev.iobaseaddr = res->start + pservice->hw_info->dec_offset;\r
1145     pservice->dec_dev.iosize     = pservice->hw_info->dec_io_size;\r
1146 \r
1147     pservice->dec_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->dec_offset);\r
1148 \r
1149     pservice->reg_size   = pservice->dec_dev.iosize;\r
1150 \r
1151     if (pservice->hw_info->hw_id != HEVC_ID) {\r
1152         pservice->enc_dev.iobaseaddr = res->start + pservice->hw_info->enc_offset;\r
1153         pservice->enc_dev.iosize     = pservice->hw_info->enc_io_size;\r
1154 \r
1155         pservice->reg_size = pservice->reg_size > pservice->enc_dev.iosize ? pservice->reg_size : pservice->enc_dev.iosize;\r
1156 \r
1157         pservice->enc_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->enc_offset);\r
1158 \r
1159         pservice->irq_enc = platform_get_irq_byname(pdev, "irq_enc");\r
1160         if (pservice->irq_enc < 0) {\r
1161             dev_err(pservice->dev, "cannot find IRQ encoder\n");\r
1162             ret = -ENXIO;\r
1163             goto err;\r
1164         }\r
1165 \r
1166         ret = devm_request_threaded_irq(pservice->dev, pservice->irq_enc, vepu_irq, vepu_isr, 0, dev_name(pservice->dev), (void *)pservice);\r
1167         if (ret) {\r
1168             dev_err(pservice->dev, "error: can't request vepu irq %d\n", pservice->irq_enc);\r
1169             goto err;\r
1170         }\r
1171     }\r
1172 \r
1173     pservice->irq_dec = platform_get_irq_byname(pdev, "irq_dec");\r
1174     if (pservice->irq_dec < 0) {\r
1175         dev_err(pservice->dev, "cannot find IRQ decoder\n");\r
1176         ret = -ENXIO;\r
1177         goto err;\r
1178     }\r
1179 \r
1180     /* get the IRQ line */\r
1181     ret = devm_request_threaded_irq(pservice->dev, pservice->irq_dec, vdpu_irq, vdpu_isr, 0, dev_name(pservice->dev), (void *)pservice);\r
1182     if (ret) {\r
1183         dev_err(pservice->dev, "error: can't request vdpu irq %d\n", pservice->irq_dec);\r
1184         goto err;\r
1185     }\r
1186 \r
1187     atomic_set(&pservice->dec_dev.irq_count_codec, 0);\r
1188     atomic_set(&pservice->dec_dev.irq_count_pp, 0);\r
1189     atomic_set(&pservice->enc_dev.irq_count_codec, 0);\r
1190     atomic_set(&pservice->enc_dev.irq_count_pp, 0);\r
1191 \r
1192     /// create device\r
1193     ret = alloc_chrdev_region(&pservice->dev_t, 0, 1, dev_name(dev));\r
1194     if (ret) {\r
1195         dev_err(dev, "alloc dev_t failed\n");\r
1196         goto err;\r
1197     }\r
1198 \r
1199     cdev_init(&pservice->cdev, &vpu_service_fops);\r
1200 \r
1201     pservice->cdev.owner = THIS_MODULE;\r
1202     pservice->cdev.ops = &vpu_service_fops;\r
1203 \r
1204     ret = cdev_add(&pservice->cdev, pservice->dev_t, 1);\r
1205 \r
1206     if (ret) {\r
1207         dev_err(dev, "add dev_t failed\n");\r
1208         goto err;\r
1209     }\r
1210 \r
1211     pservice->cls = class_create(THIS_MODULE, dev_name(dev));\r
1212 \r
1213     if (IS_ERR(pservice->cls)) {\r
1214         ret = PTR_ERR(pservice->cls);\r
1215         dev_err(dev, "class_create err:%d\n", ret);\r
1216         goto err;\r
1217     }\r
1218 \r
1219     pservice->child_dev = device_create(pservice->cls, dev, pservice->dev_t, NULL, dev_name(dev));\r
1220 \r
1221     platform_set_drvdata(pdev, pservice);\r
1222 \r
1223     if (pservice->hw_info->hw_id != HEVC_ID) {\r
1224         get_hw_info(pservice);\r
1225     }\r
1226 \r
1227 #ifdef CONFIG_DEBUG_FS\r
1228     pservice->debugfs_dir = vcodec_debugfs_create_device_dir((char*)dev_name(dev), parent);\r
1229     \r
1230     if (pservice->debugfs_dir == NULL) {\r
1231         pr_err("create debugfs dir %s failed\n", dev_name(dev));\r
1232     }\r
1233 \r
1234     pservice->debugfs_file_regs = debugfs_create_file("regs", 0664,\r
1235                     pservice->debugfs_dir, pservice,\r
1236                     &debug_vcodec_fops);\r
1237 #endif\r
1238 \r
1239     vpu_service_power_off(pservice);\r
1240     pr_info("init success\n");\r
1241 \r
1242 #if HEVC_SIM_ENABLE\r
1243     if (pservice->hw_info->hw_id == HEVC_ID) {\r
1244         simulate_init(pservice);\r
1245     }\r
1246 #endif\r
1247 \r
1248 #if HEVC_TEST_ENABLE\r
1249     hevc_test_case0(pservice);\r
1250 #endif\r
1251 \r
1252     return 0;\r
1253 \r
1254 err:\r
1255     pr_info("init failed\n");\r
1256     vpu_service_power_off(pservice);\r
1257     vpu_put_clk(pservice);\r
1258     wake_lock_destroy(&pservice->wake_lock);\r
1259 \r
1260     if (res) {\r
1261         if (regs) {\r
1262             devm_ioremap_release(&pdev->dev, res);\r
1263         }\r
1264         devm_release_mem_region(&pdev->dev, res->start, resource_size(res));\r
1265     }\r
1266 \r
1267     if (pservice->irq_enc > 0) {\r
1268         free_irq(pservice->irq_enc, (void *)pservice);\r
1269     }\r
1270 \r
1271     if (pservice->irq_dec > 0) {\r
1272         free_irq(pservice->irq_dec, (void *)pservice);\r
1273     }\r
1274 \r
1275     if (pservice->child_dev) {\r
1276         device_destroy(pservice->cls, pservice->dev_t);\r
1277         cdev_del(&pservice->cdev);\r
1278         unregister_chrdev_region(pservice->dev_t, 1);\r
1279     }\r
1280 \r
1281     if (pservice->cls) {\r
1282         class_destroy(pservice->cls);\r
1283     }\r
1284 \r
1285     return ret;\r
1286 }\r
1287 \r
1288 static int vcodec_remove(struct platform_device *pdev)\r
1289 {\r
1290     struct vpu_service_info *pservice = platform_get_drvdata(pdev);\r
1291     struct resource *res;\r
1292 \r
1293     device_destroy(pservice->cls, pservice->dev_t);\r
1294     class_destroy(pservice->cls);\r
1295     cdev_del(&pservice->cdev);\r
1296     unregister_chrdev_region(pservice->dev_t, 1);\r
1297 \r
1298     free_irq(pservice->irq_enc, (void *)&pservice->enc_dev);\r
1299     free_irq(pservice->irq_dec, (void *)&pservice->dec_dev);\r
1300     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
1301     devm_ioremap_release(&pdev->dev, res);\r
1302     devm_release_mem_region(&pdev->dev, res->start, resource_size(res));\r
1303     vpu_put_clk(pservice);\r
1304     wake_lock_destroy(&pservice->wake_lock);\r
1305     \r
1306 #ifdef CONFIG_DEBUG_FS\r
1307     if (pservice->debugfs_file_regs) {\r
1308         debugfs_remove(pservice->debugfs_file_regs);\r
1309     }\r
1310 \r
1311     if (pservice->debugfs_dir) {\r
1312         debugfs_remove(pservice->debugfs_dir);\r
1313     }\r
1314 #endif\r
1315 \r
1316     return 0;\r
1317 }\r
1318 \r
1319 #if defined(CONFIG_OF)\r
1320 static const struct of_device_id vcodec_service_dt_ids[] = {\r
1321         //{.compatible = "vpu_service",},\r
1322         {.compatible = "rockchip,hevc_service",},\r
1323     {},\r
1324 };\r
1325 #endif\r
1326 \r
1327 static struct platform_driver vcodec_driver = {\r
1328         .probe     = vcodec_probe,\r
1329     .remove        = vcodec_remove,\r
1330     .driver = {\r
1331         .name = "vcodec",\r
1332         .owner = THIS_MODULE,\r
1333 #if defined(CONFIG_OF)\r
1334         .of_match_table = of_match_ptr(vcodec_service_dt_ids),\r
1335 #endif\r
1336         },\r
1337 };\r
1338 \r
1339 static void get_hw_info(struct vpu_service_info *pservice)\r
1340 {\r
1341         VPUHwDecConfig_t *dec = &pservice->dec_config;\r
1342         VPUHwEncConfig_t *enc = &pservice->enc_config;\r
1343         u32 configReg   = pservice->dec_dev.hwregs[VPU_DEC_HWCFG0];\r
1344         u32 asicID      = pservice->dec_dev.hwregs[0];\r
1345 \r
1346         dec->h264Support    = (configReg >> DWL_H264_E) & 0x3U;\r
1347         dec->jpegSupport    = (configReg >> DWL_JPEG_E) & 0x01U;\r
1348         if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U))\r
1349                 dec->jpegSupport = JPEG_PROGRESSIVE;\r
1350         dec->mpeg4Support   = (configReg >> DWL_MPEG4_E) & 0x3U;\r
1351         dec->vc1Support     = (configReg >> DWL_VC1_E) & 0x3U;\r
1352         dec->mpeg2Support   = (configReg >> DWL_MPEG2_E) & 0x01U;\r
1353         dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U;\r
1354         dec->refBufSupport  = (configReg >> DWL_REF_BUFF_E) & 0x01U;\r
1355         dec->vp6Support     = (configReg >> DWL_VP6_E) & 0x01U;\r
1356 #if !defined(CONFIG_ARCH_RK319X)\r
1357     /// invalidate max decode picture width value in rk319x vpu\r
1358         dec->maxDecPicWidth = configReg & 0x07FFU;\r
1359 #else\r
1360     dec->maxDecPicWidth = 3840;\r
1361 #endif\r
1362 \r
1363         /* 2nd Config register */\r
1364         configReg   = pservice->dec_dev.hwregs[VPU_DEC_HWCFG1];\r
1365         if (dec->refBufSupport) {\r
1366                 if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U)\r
1367                         dec->refBufSupport |= 2;\r
1368                 if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U)\r
1369                         dec->refBufSupport |= 4;\r
1370         }\r
1371         dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U;\r
1372         dec->vp7Support     = (configReg >> DWL_VP7_E) & 0x01U;\r
1373         dec->vp8Support     = (configReg >> DWL_VP8_E) & 0x01U;\r
1374         dec->avsSupport     = (configReg >> DWL_AVS_E) & 0x01U;\r
1375 \r
1376         /* JPEG xtensions */\r
1377         if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) {\r
1378                 dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U;\r
1379         } else {\r
1380                 dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED;\r
1381         }\r
1382 \r
1383         if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) ) {\r
1384                 dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U;\r
1385         } else {\r
1386                 dec->rvSupport = RV_NOT_SUPPORTED;\r
1387         }\r
1388 \r
1389         dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U;\r
1390 \r
1391         if (dec->refBufSupport && (asicID >> 16) == 0x6731U ) {\r
1392                 dec->refBufSupport |= 8; /* enable HW support for offset */\r
1393         }\r
1394 \r
1395 #if !defined(CONFIG_ARCH_RK319X)\r
1396     /// invalidate fuse register value in rk319x vpu\r
1397         {\r
1398         VPUHwFuseStatus_t hwFuseSts;\r
1399         /* Decoder fuse configuration */\r
1400         u32 fuseReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];\r
1401 \r
1402         hwFuseSts.h264SupportFuse = (fuseReg >> DWL_H264_FUSE_E) & 0x01U;\r
1403         hwFuseSts.mpeg4SupportFuse = (fuseReg >> DWL_MPEG4_FUSE_E) & 0x01U;\r
1404         hwFuseSts.mpeg2SupportFuse = (fuseReg >> DWL_MPEG2_FUSE_E) & 0x01U;\r
1405         hwFuseSts.sorensonSparkSupportFuse = (fuseReg >> DWL_SORENSONSPARK_FUSE_E) & 0x01U;\r
1406         hwFuseSts.jpegSupportFuse = (fuseReg >> DWL_JPEG_FUSE_E) & 0x01U;\r
1407         hwFuseSts.vp6SupportFuse = (fuseReg >> DWL_VP6_FUSE_E) & 0x01U;\r
1408         hwFuseSts.vc1SupportFuse = (fuseReg >> DWL_VC1_FUSE_E) & 0x01U;\r
1409         hwFuseSts.jpegProgSupportFuse = (fuseReg >> DWL_PJPEG_FUSE_E) & 0x01U;\r
1410         hwFuseSts.rvSupportFuse = (fuseReg >> DWL_RV_FUSE_E) & 0x01U;\r
1411         hwFuseSts.avsSupportFuse = (fuseReg >> DWL_AVS_FUSE_E) & 0x01U;\r
1412         hwFuseSts.vp7SupportFuse = (fuseReg >> DWL_VP7_FUSE_E) & 0x01U;\r
1413         hwFuseSts.vp8SupportFuse = (fuseReg >> DWL_VP8_FUSE_E) & 0x01U;\r
1414         hwFuseSts.customMpeg4SupportFuse = (fuseReg >> DWL_CUSTOM_MPEG4_FUSE_E) & 0x01U;\r
1415         hwFuseSts.mvcSupportFuse = (fuseReg >> DWL_MVC_FUSE_E) & 0x01U;\r
1416 \r
1417         /* check max. decoder output width */\r
1418 \r
1419         if (fuseReg & 0x8000U)\r
1420                 hwFuseSts.maxDecPicWidthFuse = 1920;\r
1421         else if (fuseReg & 0x4000U)\r
1422                 hwFuseSts.maxDecPicWidthFuse = 1280;\r
1423         else if (fuseReg & 0x2000U)\r
1424                 hwFuseSts.maxDecPicWidthFuse = 720;\r
1425         else if (fuseReg & 0x1000U)\r
1426                 hwFuseSts.maxDecPicWidthFuse = 352;\r
1427         else    /* remove warning */\r
1428                 hwFuseSts.maxDecPicWidthFuse = 352;\r
1429 \r
1430         hwFuseSts.refBufSupportFuse = (fuseReg >> DWL_REF_BUFF_FUSE_E) & 0x01U;\r
1431 \r
1432         /* Pp configuration */\r
1433         configReg = pservice->dec_dev.hwregs[VPU_PP_HW_SYNTH_CFG];\r
1434 \r
1435         if ((configReg >> DWL_PP_E) & 0x01U) {\r
1436                 dec->ppSupport = 1;\r
1437                 dec->maxPpOutPicWidth = configReg & 0x07FFU;\r
1438                 /*pHwCfg->ppConfig = (configReg >> DWL_CFG_E) & 0x0FU; */\r
1439                 dec->ppConfig = configReg;\r
1440         } else {\r
1441                 dec->ppSupport = 0;\r
1442                 dec->maxPpOutPicWidth = 0;\r
1443                 dec->ppConfig = 0;\r
1444         }\r
1445 \r
1446         /* check the HW versio */\r
1447         if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) {\r
1448                 /* Pp configuration */\r
1449                 configReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];\r
1450 \r
1451                 if ((configReg >> DWL_PP_E) & 0x01U) {\r
1452                         /* Pp fuse configuration */\r
1453                         u32 fuseRegPp = pservice->dec_dev.hwregs[VPU_PP_HW_FUSE_CFG];\r
1454 \r
1455                         if ((fuseRegPp >> DWL_PP_FUSE_E) & 0x01U) {\r
1456                                 hwFuseSts.ppSupportFuse = 1;\r
1457                                 /* check max. pp output width */\r
1458                                 if      (fuseRegPp & 0x8000U) hwFuseSts.maxPpOutPicWidthFuse = 1920;\r
1459                                 else if (fuseRegPp & 0x4000U) hwFuseSts.maxPpOutPicWidthFuse = 1280;\r
1460                                 else if (fuseRegPp & 0x2000U) hwFuseSts.maxPpOutPicWidthFuse = 720;\r
1461                                 else if (fuseRegPp & 0x1000U) hwFuseSts.maxPpOutPicWidthFuse = 352;\r
1462                                 else                          hwFuseSts.maxPpOutPicWidthFuse = 352;\r
1463                                 hwFuseSts.ppConfigFuse = fuseRegPp;\r
1464                         } else {\r
1465                                 hwFuseSts.ppSupportFuse = 0;\r
1466                                 hwFuseSts.maxPpOutPicWidthFuse = 0;\r
1467                                 hwFuseSts.ppConfigFuse = 0;\r
1468                         }\r
1469                 } else {\r
1470                         hwFuseSts.ppSupportFuse = 0;\r
1471                         hwFuseSts.maxPpOutPicWidthFuse = 0;\r
1472                         hwFuseSts.ppConfigFuse = 0;\r
1473                 }\r
1474 \r
1475                 if (dec->maxDecPicWidth > hwFuseSts.maxDecPicWidthFuse)\r
1476                         dec->maxDecPicWidth = hwFuseSts.maxDecPicWidthFuse;\r
1477                 if (dec->maxPpOutPicWidth > hwFuseSts.maxPpOutPicWidthFuse)\r
1478                         dec->maxPpOutPicWidth = hwFuseSts.maxPpOutPicWidthFuse;\r
1479                 if (!hwFuseSts.h264SupportFuse) dec->h264Support = H264_NOT_SUPPORTED;\r
1480                 if (!hwFuseSts.mpeg4SupportFuse) dec->mpeg4Support = MPEG4_NOT_SUPPORTED;\r
1481                 if (!hwFuseSts.customMpeg4SupportFuse) dec->customMpeg4Support = MPEG4_CUSTOM_NOT_SUPPORTED;\r
1482                 if (!hwFuseSts.jpegSupportFuse) dec->jpegSupport = JPEG_NOT_SUPPORTED;\r
1483                 if ((dec->jpegSupport == JPEG_PROGRESSIVE) && !hwFuseSts.jpegProgSupportFuse)\r
1484                         dec->jpegSupport = JPEG_BASELINE;\r
1485                 if (!hwFuseSts.mpeg2SupportFuse) dec->mpeg2Support = MPEG2_NOT_SUPPORTED;\r
1486                 if (!hwFuseSts.vc1SupportFuse) dec->vc1Support = VC1_NOT_SUPPORTED;\r
1487                 if (!hwFuseSts.vp6SupportFuse) dec->vp6Support = VP6_NOT_SUPPORTED;\r
1488                 if (!hwFuseSts.vp7SupportFuse) dec->vp7Support = VP7_NOT_SUPPORTED;\r
1489                 if (!hwFuseSts.vp8SupportFuse) dec->vp8Support = VP8_NOT_SUPPORTED;\r
1490                 if (!hwFuseSts.ppSupportFuse) dec->ppSupport = PP_NOT_SUPPORTED;\r
1491 \r
1492                 /* check the pp config vs fuse status */\r
1493                 if ((dec->ppConfig & 0xFC000000) && ((hwFuseSts.ppConfigFuse & 0xF0000000) >> 5)) {\r
1494                         u32 deInterlace = ((dec->ppConfig & PP_DEINTERLACING) >> 25);\r
1495                         u32 alphaBlend  = ((dec->ppConfig & PP_ALPHA_BLENDING) >> 24);\r
1496                         u32 deInterlaceFuse = (((hwFuseSts.ppConfigFuse >> 5) & PP_DEINTERLACING) >> 25);\r
1497                         u32 alphaBlendFuse  = (((hwFuseSts.ppConfigFuse >> 5) & PP_ALPHA_BLENDING) >> 24);\r
1498 \r
1499                         if (deInterlace && !deInterlaceFuse) dec->ppConfig &= 0xFD000000;\r
1500                         if (alphaBlend && !alphaBlendFuse) dec->ppConfig &= 0xFE000000;\r
1501                 }\r
1502                 if (!hwFuseSts.sorensonSparkSupportFuse) dec->sorensonSparkSupport = SORENSON_SPARK_NOT_SUPPORTED;\r
1503                 if (!hwFuseSts.refBufSupportFuse)   dec->refBufSupport = REF_BUF_NOT_SUPPORTED;\r
1504                 if (!hwFuseSts.rvSupportFuse)       dec->rvSupport = RV_NOT_SUPPORTED;\r
1505                 if (!hwFuseSts.avsSupportFuse)      dec->avsSupport = AVS_NOT_SUPPORTED;\r
1506                 if (!hwFuseSts.mvcSupportFuse)      dec->mvcSupport = MVC_NOT_SUPPORTED;\r
1507         }\r
1508         }\r
1509 #endif\r
1510         configReg = pservice->enc_dev.hwregs[63];\r
1511         enc->maxEncodedWidth = configReg & ((1 << 11) - 1);\r
1512         enc->h264Enabled = (configReg >> 27) & 1;\r
1513         enc->mpeg4Enabled = (configReg >> 26) & 1;\r
1514         enc->jpegEnabled = (configReg >> 25) & 1;\r
1515         enc->vsEnabled = (configReg >> 24) & 1;\r
1516         enc->rgbEnabled = (configReg >> 28) & 1;\r
1517         //enc->busType = (configReg >> 20) & 15;\r
1518         //enc->synthesisLanguage = (configReg >> 16) & 15;\r
1519         //enc->busWidth = (configReg >> 12) & 15;\r
1520         enc->reg_size = pservice->reg_size;\r
1521         enc->reserv[0] = enc->reserv[1] = 0;\r
1522 \r
1523         pservice->auto_freq = soc_is_rk2928g() || soc_is_rk2928l() || soc_is_rk2926();\r
1524         if (pservice->auto_freq) {\r
1525                 printk("vpu_service set to auto frequency mode\n");\r
1526                 atomic_set(&pservice->freq_status, VPU_FREQ_BUT);\r
1527         }\r
1528         pservice->bug_dec_addr = cpu_is_rk30xx();\r
1529         //printk("cpu 3066b bug %d\n", service.bug_dec_addr);\r
1530 }\r
1531 \r
1532 static irqreturn_t vdpu_irq(int irq, void *dev_id)\r
1533 {\r
1534     struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
1535     vpu_device *dev = &pservice->dec_dev;\r
1536         u32 irq_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);\r
1537 \r
1538         pr_debug("dec_irq\n");\r
1539 \r
1540         if (irq_status & DEC_INTERRUPT_BIT) {\r
1541                 pr_debug("dec_isr dec %x\n", irq_status);\r
1542                 if ((irq_status & 0x40001) == 0x40001)\r
1543                 {\r
1544                         do {\r
1545                                 irq_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);\r
1546                         } while ((irq_status & 0x40001) == 0x40001);\r
1547                 }\r
1548 \r
1549                 /* clear dec IRQ */\r
1550         if (pservice->hw_info->hw_id != HEVC_ID) {\r
1551             writel(irq_status & (~DEC_INTERRUPT_BIT|DEC_BUFFER_EMPTY_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER);\r
1552         } else {\r
1553             /*writel(irq_status \r
1554               & (~(DEC_INTERRUPT_BIT|HEVC_DEC_INT_RAW_BIT|HEVC_DEC_STR_ERROR_BIT|HEVC_DEC_BUS_ERROR_BIT|HEVC_DEC_BUFFER_EMPTY_BIT)), \r
1555                    dev->hwregs + DEC_INTERRUPT_REGISTER);*/\r
1556 \r
1557             writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER);\r
1558         }\r
1559                 atomic_add(1, &dev->irq_count_codec);\r
1560         }\r
1561 \r
1562     if (pservice->hw_info->hw_id != HEVC_ID) {\r
1563         irq_status  = readl(dev->hwregs + PP_INTERRUPT_REGISTER);\r
1564         if (irq_status & PP_INTERRUPT_BIT) {\r
1565             pr_debug("vdpu_isr pp  %x\n", irq_status);\r
1566             /* clear pp IRQ */\r
1567             writel(irq_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);\r
1568             atomic_add(1, &dev->irq_count_pp);\r
1569         }\r
1570     }\r
1571 \r
1572     pservice->irq_status = irq_status;\r
1573 \r
1574         return IRQ_WAKE_THREAD;\r
1575 }\r
1576 \r
1577 static irqreturn_t vdpu_isr(int irq, void *dev_id)\r
1578 {\r
1579     struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
1580     vpu_device *dev = &pservice->dec_dev;\r
1581 \r
1582         mutex_lock(&pservice->lock);\r
1583         if (atomic_read(&dev->irq_count_codec)) {\r
1584 #if VPU_SERVICE_SHOW_TIME\r
1585                 do_gettimeofday(&dec_end);\r
1586                 pr_info("dec task: %ld ms\n",\r
1587                         (dec_end.tv_sec  - dec_start.tv_sec)  * 1000 +\r
1588                         (dec_end.tv_usec - dec_start.tv_usec) / 1000);\r
1589 #endif\r
1590                 atomic_sub(1, &dev->irq_count_codec);\r
1591                 if (NULL == pservice->reg_codec) {\r
1592                         pr_err("error: dec isr with no task waiting\n");\r
1593                 } else {\r
1594                         reg_from_run_to_done(pservice, pservice->reg_codec);\r
1595                 }\r
1596         }\r
1597 \r
1598         if (atomic_read(&dev->irq_count_pp)) {\r
1599 \r
1600 #if VPU_SERVICE_SHOW_TIME\r
1601                 do_gettimeofday(&pp_end);\r
1602                 printk("pp  task: %ld ms\n",\r
1603                         (pp_end.tv_sec  - pp_start.tv_sec)  * 1000 +\r
1604                         (pp_end.tv_usec - pp_start.tv_usec) / 1000);\r
1605 #endif\r
1606 \r
1607                 atomic_sub(1, &dev->irq_count_pp);\r
1608                 if (NULL == pservice->reg_pproc) {\r
1609                         pr_err("error: pp isr with no task waiting\n");\r
1610                 } else {\r
1611                         reg_from_run_to_done(pservice, pservice->reg_pproc);\r
1612                 }\r
1613         }\r
1614         try_set_reg(pservice);\r
1615         mutex_unlock(&pservice->lock);\r
1616         return IRQ_HANDLED;\r
1617 }\r
1618 \r
1619 static irqreturn_t vepu_irq(int irq, void *dev_id)\r
1620 {\r
1621         //struct vpu_device *dev = (struct vpu_device *) dev_id;\r
1622     struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
1623     vpu_device *dev = &pservice->enc_dev;\r
1624         u32 irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER);\r
1625 \r
1626         pr_debug("vepu_irq irq status %x\n", irq_status);\r
1627 \r
1628 #if VPU_SERVICE_SHOW_TIME\r
1629         do_gettimeofday(&enc_end);\r
1630         pr_info("enc task: %ld ms\n",\r
1631                 (enc_end.tv_sec  - enc_start.tv_sec)  * 1000 +\r
1632                 (enc_end.tv_usec - enc_start.tv_usec) / 1000);\r
1633 #endif\r
1634 \r
1635         if (likely(irq_status & ENC_INTERRUPT_BIT)) {\r
1636                 /* clear enc IRQ */\r
1637                 writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);\r
1638                 atomic_add(1, &dev->irq_count_codec);\r
1639         }\r
1640 \r
1641         return IRQ_WAKE_THREAD;\r
1642 }\r
1643 \r
1644 static irqreturn_t vepu_isr(int irq, void *dev_id)\r
1645 {\r
1646         //struct vpu_device *dev = (struct vpu_device *) dev_id;\r
1647     struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
1648     vpu_device *dev = &pservice->enc_dev;\r
1649 \r
1650         mutex_lock(&pservice->lock);\r
1651         if (atomic_read(&dev->irq_count_codec)) {\r
1652                 atomic_sub(1, &dev->irq_count_codec);\r
1653                 if (NULL == pservice->reg_codec) {\r
1654                         pr_err("error: enc isr with no task waiting\n");\r
1655                 } else {\r
1656                         reg_from_run_to_done(pservice, pservice->reg_codec);\r
1657                 }\r
1658         }\r
1659         try_set_reg(pservice);\r
1660         mutex_unlock(&pservice->lock);\r
1661         return IRQ_HANDLED;\r
1662 }\r
1663 \r
1664 static int __init vcodec_service_init(void)\r
1665 {\r
1666     int ret;\r
1667 \r
1668     if ((ret = platform_driver_register(&vcodec_driver)) != 0) {\r
1669         pr_err("Platform device register failed (%d).\n", ret);\r
1670         return ret;\r
1671     }\r
1672 \r
1673 #ifdef CONFIG_DEBUG_FS\r
1674     vcodec_debugfs_init();\r
1675 #endif\r
1676 \r
1677     return ret;\r
1678 }\r
1679 \r
1680 static void __exit vcodec_service_exit(void)\r
1681 {\r
1682 #ifdef CONFIG_DEBUG_FS\r
1683     vcodec_debugfs_exit();\r
1684 #endif\r
1685 \r
1686         platform_driver_unregister(&vcodec_driver);\r
1687 }\r
1688 \r
1689 module_init(vcodec_service_init);\r
1690 module_exit(vcodec_service_exit);\r
1691 \r
1692 #ifdef CONFIG_DEBUG_FS\r
1693 #include <linux/seq_file.h>\r
1694 \r
1695 static int vcodec_debugfs_init()\r
1696 {\r
1697     parent = debugfs_create_dir("vcodec", NULL);\r
1698     if (!parent)\r
1699         return -1;\r
1700 \r
1701     return 0;\r
1702 }\r
1703 \r
1704 static void vcodec_debugfs_exit()\r
1705 {\r
1706     debugfs_remove(parent);\r
1707 }\r
1708 \r
1709 static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent)\r
1710 {\r
1711     return debugfs_create_dir(dirname, parent);\r
1712 }\r
1713 \r
1714 static int debug_vcodec_show(struct seq_file *s, void *unused)\r
1715 {\r
1716         struct vpu_service_info *pservice = s->private;\r
1717     unsigned int i, n;\r
1718         vpu_reg *reg, *reg_tmp;\r
1719         vpu_session *session, *session_tmp;\r
1720 \r
1721         mutex_lock(&pservice->lock);\r
1722         vpu_service_power_on(pservice);\r
1723     if (pservice->hw_info->hw_id != HEVC_ID) {\r
1724         seq_printf(s, "\nENC Registers:\n");\r
1725         n = pservice->enc_dev.iosize >> 2;\r
1726         for (i = 0; i < n; i++) {\r
1727             seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->enc_dev.hwregs + i));\r
1728         }\r
1729     }\r
1730         seq_printf(s, "\nDEC Registers:\n");\r
1731         n = pservice->dec_dev.iosize >> 2;\r
1732         for (i = 0; i < n; i++) {\r
1733                 seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i));\r
1734         }\r
1735 \r
1736         seq_printf(s, "\nvpu service status:\n");\r
1737         list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) {\r
1738                 seq_printf(s, "session pid %d type %d:\n", session->pid, session->type);\r
1739                 //seq_printf(s, "waiting reg set %d\n");\r
1740                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {\r
1741                         seq_printf(s, "waiting register set\n");\r
1742                 }\r
1743                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {\r
1744                         seq_printf(s, "running register set\n");\r
1745                 }\r
1746                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {\r
1747                         seq_printf(s, "done    register set\n");\r
1748                 }\r
1749         }\r
1750         mutex_unlock(&pservice->lock);\r
1751 \r
1752     return 0;\r
1753 }\r
1754 \r
1755 static int debug_vcodec_open(struct inode *inode, struct file *file)\r
1756 {\r
1757         return single_open(file, debug_vcodec_show, inode->i_private);\r
1758 }\r
1759 \r
1760 #endif\r
1761 \r
1762 #if HEVC_TEST_ENABLE\r
1763 #include "hevc_test_inc/pps_00.h"\r
1764 #include "hevc_test_inc/register_00.h"\r
1765 #include "hevc_test_inc/rps_00.h"\r
1766 #include "hevc_test_inc/scaling_list_00.h"\r
1767 #include "hevc_test_inc/stream_00.h"\r
1768 \r
1769 #include "hevc_test_inc/pps_01.h"\r
1770 #include "hevc_test_inc/register_01.h"\r
1771 #include "hevc_test_inc/rps_01.h"\r
1772 #include "hevc_test_inc/scaling_list_01.h"\r
1773 #include "hevc_test_inc/stream_01.h"\r
1774 \r
1775 #include "hevc_test_inc/cabac.h"\r
1776 \r
1777 #define TEST_CNT    2\r
1778 static int hevc_test_case0(vpu_service_info *pservice)\r
1779 {\r
1780     vpu_session session;\r
1781     vpu_reg *reg; \r
1782     unsigned long size = sizeof(register_00); // registers array length\r
1783     int testidx = 0;\r
1784     int ret = 0;\r
1785 \r
1786     u8 *pps_tbl[TEST_CNT];\r
1787     u8 *register_tbl[TEST_CNT];\r
1788     u8 *rps_tbl[TEST_CNT];\r
1789     u8 *scaling_list_tbl[TEST_CNT];\r
1790     u8 *stream_tbl[TEST_CNT];\r
1791 \r
1792     int stream_size[2];\r
1793 \r
1794     u32 phy_pps;\r
1795     u32 phy_rps;\r
1796     u32 phy_scl;\r
1797     u32 phy_str;\r
1798     u32 phy_yuv;\r
1799     u32 phy_cabac;\r
1800 \r
1801     u8 *pps;\r
1802     u8 *yuv;\r
1803     int i;\r
1804     \r
1805     pps_tbl[0] = pps_00;\r
1806     pps_tbl[1] = pps_01;\r
1807 \r
1808     register_tbl[0] = register_00;\r
1809     register_tbl[1] = register_01;\r
1810     \r
1811     rps_tbl[0] = rps_00;\r
1812     rps_tbl[1] = rps_01;\r
1813     \r
1814     scaling_list_tbl[0] = scaling_list_00;\r
1815     scaling_list_tbl[1] = scaling_list_01;\r
1816 \r
1817     stream_tbl[0] = stream_00;\r
1818     stream_tbl[1] = stream_01;\r
1819 \r
1820     stream_size[0] = sizeof(stream_00);\r
1821     stream_size[1] = sizeof(stream_01);\r
1822 \r
1823     // create session\r
1824     session.pid = current->pid;\r
1825     session.type = VPU_DEC;\r
1826     INIT_LIST_HEAD(&session.waiting);\r
1827         INIT_LIST_HEAD(&session.running);\r
1828         INIT_LIST_HEAD(&session.done);\r
1829         INIT_LIST_HEAD(&session.list_session);\r
1830         init_waitqueue_head(&session.wait);\r
1831         atomic_set(&session.task_running, 0);\r
1832         list_add_tail(&session.list_session, &pservice->session);\r
1833 \r
1834     while (testidx < TEST_CNT) {\r
1835         // create registers\r
1836         reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);\r
1837         if (NULL == reg) {\r
1838             pr_err("error: kmalloc fail in reg_init\n");\r
1839             return -1;\r
1840         }\r
1841 \r
1842         if (size > pservice->reg_size) {\r
1843             printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
1844             size = pservice->reg_size;\r
1845         }\r
1846         reg->session = &session;\r
1847         reg->type = session.type;\r
1848         reg->size = size;\r
1849         reg->freq = VPU_FREQ_DEFAULT;\r
1850         reg->reg = (unsigned long *)&reg[1];\r
1851         INIT_LIST_HEAD(&reg->session_link);\r
1852         INIT_LIST_HEAD(&reg->status_link);\r
1853 \r
1854         pps = kmalloc(sizeof(pps_00), GFP_KERNEL);\r
1855         yuv = kzalloc(256*256*3/2, GFP_KERNEL);\r
1856         memcpy(pps, pps_tbl[testidx], sizeof(pps_00));\r
1857 \r
1858         // TODO: stuff registers\r
1859         memcpy(&reg->reg[0], register_tbl[testidx], sizeof(register_00));\r
1860 \r
1861         // TODO: replace reigster address\r
1862         phy_pps = virt_to_phys(pps);\r
1863         phy_rps = virt_to_phys(rps_tbl[testidx]);\r
1864         phy_scl = virt_to_phys(scaling_list_tbl[testidx]);\r
1865         phy_str = virt_to_phys(stream_tbl[testidx]);\r
1866         phy_yuv = virt_to_phys(yuv);\r
1867         phy_cabac = virt_to_phys(Cabac_table);\r
1868 \r
1869         for (i=0; i<64; i++) {\r
1870             u32 scaling_offset;\r
1871             u32 tmp;\r
1872 \r
1873             scaling_offset = (u32)pps[i*80+74];\r
1874             scaling_offset += (u32)pps[i*80+75] << 8;\r
1875             scaling_offset += (u32)pps[i*80+76] << 16;\r
1876             scaling_offset += (u32)pps[i*80+77] << 24;\r
1877 \r
1878             tmp = phy_scl + scaling_offset;\r
1879 \r
1880             pps[i*80+74] = tmp & 0xff;\r
1881             pps[i*80+75] = (tmp >> 8) & 0xff;\r
1882             pps[i*80+76] = (tmp >> 16) & 0xff;\r
1883             pps[i*80+77] = (tmp >> 24) & 0xff;\r
1884         }\r
1885 \r
1886         dmac_flush_range(&pps[0], &pps[sizeof(pps_00) - 1]);\r
1887         outer_flush_range(phy_pps, phy_pps + sizeof(pps_00) - 1);\r
1888 \r
1889         printk("%s %d, phy stream %08x, phy pps %08x, phy rps %08x\n", __func__, __LINE__, phy_str, phy_pps, phy_rps);\r
1890 \r
1891         reg->reg[4] = phy_str;\r
1892         reg->reg[5] = ((stream_size[testidx]+15)&(~15))+64;\r
1893         reg->reg[6] = phy_cabac;\r
1894         reg->reg[7] = phy_yuv;\r
1895         reg->reg[42] = phy_pps;\r
1896         reg->reg[43] = phy_rps;\r
1897 \r
1898         mutex_lock(&pservice->lock);\r
1899         list_add_tail(&reg->status_link, &pservice->waiting);\r
1900         list_add_tail(&reg->session_link, &session.waiting);\r
1901         mutex_unlock(&pservice->lock);\r
1902 \r
1903         printk("%s %d %p\n", __func__, __LINE__, pservice);\r
1904 \r
1905         // stuff hardware\r
1906         try_set_reg(pservice);\r
1907 \r
1908         // wait for result\r
1909         ret = wait_event_timeout(session.wait, !list_empty(&session.done), VPU_TIMEOUT_DELAY);\r
1910         if (!list_empty(&session.done)) {\r
1911             if (ret < 0) {\r
1912                 pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session.pid, ret);\r
1913             }\r
1914             ret = 0;\r
1915         } else {\r
1916             if (unlikely(ret < 0)) {\r
1917                 pr_err("error: pid %d wait task ret %d\n", session.pid, ret);\r
1918             } else if (0 == ret) {\r
1919                 pr_err("error: pid %d wait %d task done timeout\n", session.pid, atomic_read(&session.task_running));\r
1920                 ret = -ETIMEDOUT;\r
1921             }\r
1922         }\r
1923         if (ret < 0) {\r
1924             int task_running = atomic_read(&session.task_running);\r
1925             int n;\r
1926             mutex_lock(&pservice->lock);\r
1927             vpu_service_dump(pservice);\r
1928             if (task_running) {\r
1929                 atomic_set(&session.task_running, 0);\r
1930                 atomic_sub(task_running, &pservice->total_running);\r
1931                 printk("%d task is running but not return, reset hardware...", task_running);\r
1932                 vpu_reset(pservice);\r
1933                 printk("done\n");\r
1934             }\r
1935             vpu_service_session_clear(pservice, &session);\r
1936             mutex_unlock(&pservice->lock);\r
1937 \r
1938             printk("\nDEC Registers:\n");\r
1939                 n = pservice->dec_dev.iosize >> 2;\r
1940                 for (i=0; i<n; i++) {\r
1941                         printk("\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i));\r
1942                 }\r
1943 \r
1944             pr_err("test index %d failed\n", testidx);\r
1945             kfree(pps);\r
1946             kfree(yuv);\r
1947             break;\r
1948         } else {\r
1949             pr_info("test index %d success\n", testidx);\r
1950 \r
1951             vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link);\r
1952 \r
1953             for (i=0; i<68; i++) {\r
1954                 if (i % 4 == 0) {\r
1955                     printk("%02d: ", i);\r
1956                 }\r
1957                 printk("%08x ", reg->reg[i]);\r
1958                 if ((i+1) % 4 == 0) {\r
1959                     printk("\n");\r
1960                 }\r
1961             }\r
1962 \r
1963             testidx++;\r
1964         }\r
1965 \r
1966         reg_deinit(pservice, reg);\r
1967         kfree(pps);\r
1968         kfree(yuv);\r
1969     }\r
1970 \r
1971     return 0;\r
1972 }\r
1973 \r
1974 #endif\r
1975 \r