Merge remote-tracking branch 'origin/develop-3.10' into develop-3.10-next
[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 #include <linux/rockchip/cpu.h>\r
37 #include <linux/rockchip/cru.h>\r
38 \r
39 #include <asm/cacheflush.h>\r
40 #include <linux/uaccess.h>\r
41 #include <linux/rockchip/grf.h>\r
42 \r
43 #if defined(CONFIG_ION_ROCKCHIP)\r
44 #include <linux/rockchip_ion.h>\r
45 #endif\r
46 \r
47 #if defined(CONFIG_ROCKCHIP_IOMMU) & defined(CONFIG_ION_ROCKCHIP)\r
48 #define CONFIG_VCODEC_MMU\r
49 #endif\r
50 \r
51 #ifdef CONFIG_VCODEC_MMU\r
52 #include <linux/rockchip/iovmm.h>\r
53 #include <linux/rockchip/sysmmu.h>\r
54 #include <linux/dma-buf.h>\r
55 #endif\r
56 \r
57 #ifdef CONFIG_DEBUG_FS\r
58 #include <linux/debugfs.h>\r
59 #endif\r
60 \r
61 #if defined(CONFIG_ARCH_RK319X)\r
62 #include <mach/grf.h>\r
63 #endif\r
64 \r
65 #include "vcodec_service.h"\r
66 \r
67 #define HEVC_TEST_ENABLE        0\r
68 #define HEVC_SIM_ENABLE         0\r
69 #define VCODEC_CLOCK_ENABLE     1\r
70 \r
71 typedef enum {\r
72         VPU_DEC_ID_9190         = 0x6731,\r
73         VPU_ID_8270             = 0x8270,\r
74         VPU_ID_4831             = 0x4831,\r
75         HEVC_ID                 = 0x6867,\r
76 } VPU_HW_ID;\r
77 \r
78 typedef enum {\r
79         VPU_DEC_TYPE_9190       = 0,\r
80         VPU_ENC_TYPE_8270       = 0x100,\r
81         VPU_ENC_TYPE_4831       ,\r
82 } VPU_HW_TYPE_E;\r
83 \r
84 typedef enum VPU_FREQ {\r
85         VPU_FREQ_200M,\r
86         VPU_FREQ_266M,\r
87         VPU_FREQ_300M,\r
88         VPU_FREQ_400M,\r
89         VPU_FREQ_500M,\r
90         VPU_FREQ_600M,\r
91         VPU_FREQ_DEFAULT,\r
92         VPU_FREQ_BUT,\r
93 } VPU_FREQ;\r
94 \r
95 typedef struct {\r
96         VPU_HW_ID               hw_id;\r
97         unsigned long           hw_addr;\r
98         unsigned long           enc_offset;\r
99         unsigned long           enc_reg_num;\r
100         unsigned long           enc_io_size;\r
101         unsigned long           dec_offset;\r
102         unsigned long           dec_reg_num;\r
103         unsigned long           dec_io_size;\r
104 } VPU_HW_INFO_E;\r
105 \r
106 #define VPU_SERVICE_SHOW_TIME                   0\r
107 \r
108 #if VPU_SERVICE_SHOW_TIME\r
109 static struct timeval enc_start, enc_end;\r
110 static struct timeval dec_start, dec_end;\r
111 static struct timeval pp_start,  pp_end;\r
112 #endif\r
113 \r
114 #define MHZ                                     (1000*1000)\r
115 \r
116 #define REG_NUM_9190_DEC                        (60)\r
117 #define REG_NUM_9190_PP                         (41)\r
118 #define REG_NUM_9190_DEC_PP                     (REG_NUM_9190_DEC+REG_NUM_9190_PP)\r
119 \r
120 #define REG_NUM_DEC_PP                          (REG_NUM_9190_DEC+REG_NUM_9190_PP)\r
121 \r
122 #define REG_NUM_ENC_8270                        (96)\r
123 #define REG_SIZE_ENC_8270                       (0x200)\r
124 #define REG_NUM_ENC_4831                        (164)\r
125 #define REG_SIZE_ENC_4831                       (0x400)\r
126 \r
127 #define REG_NUM_HEVC_DEC                        (68)\r
128 \r
129 #define SIZE_REG(reg)                           ((reg)*4)\r
130 \r
131 static VPU_HW_INFO_E vpu_hw_set[] = {\r
132         [0] = {\r
133                 .hw_id          = VPU_ID_8270,\r
134                 .hw_addr        = 0,\r
135                 .enc_offset     = 0x0,\r
136                 .enc_reg_num    = REG_NUM_ENC_8270,\r
137                 .enc_io_size    = REG_NUM_ENC_8270 * 4,\r
138                 .dec_offset     = REG_SIZE_ENC_8270,\r
139                 .dec_reg_num    = REG_NUM_9190_DEC_PP,\r
140                 .dec_io_size    = REG_NUM_9190_DEC_PP * 4,\r
141         },\r
142         [1] = {\r
143                 .hw_id          = VPU_ID_4831,\r
144                 .hw_addr        = 0,\r
145                 .enc_offset     = 0x0,\r
146                 .enc_reg_num    = REG_NUM_ENC_4831,\r
147                 .enc_io_size    = REG_NUM_ENC_4831 * 4,\r
148                 .dec_offset     = REG_SIZE_ENC_4831,\r
149                 .dec_reg_num    = REG_NUM_9190_DEC_PP,\r
150                 .dec_io_size    = REG_NUM_9190_DEC_PP * 4,\r
151         },\r
152         [2] = {\r
153                 .hw_id          = HEVC_ID,\r
154                 .hw_addr        = 0,\r
155                 .dec_offset     = 0x0,\r
156                 .dec_reg_num    = REG_NUM_HEVC_DEC,\r
157                 .dec_io_size    = REG_NUM_HEVC_DEC * 4,\r
158         },\r
159         [3] = {\r
160                 .hw_id          = VPU_DEC_ID_9190,\r
161                 .hw_addr        = 0,\r
162                 .enc_offset     = 0x0,\r
163                 .enc_reg_num    = 0,\r
164                 .enc_io_size    = 0,\r
165                 .dec_offset     = REG_SIZE_ENC_4831,\r
166                 .dec_reg_num    = REG_NUM_9190_DEC_PP,\r
167                 .dec_io_size    = REG_NUM_9190_DEC_PP * 4,\r
168         },\r
169 \r
170 };\r
171 \r
172 \r
173 #define DEC_INTERRUPT_REGISTER                  1\r
174 #define PP_INTERRUPT_REGISTER                   60\r
175 #define ENC_INTERRUPT_REGISTER                  1\r
176 \r
177 #define DEC_INTERRUPT_BIT                       0x100\r
178 #define DEC_BUFFER_EMPTY_BIT                    0x4000\r
179 #define PP_INTERRUPT_BIT                        0x100\r
180 #define ENC_INTERRUPT_BIT                       0x1\r
181 \r
182 #define HEVC_DEC_INT_RAW_BIT                    0x200\r
183 #define HEVC_DEC_STR_ERROR_BIT                  0x4000\r
184 #define HEVC_DEC_BUS_ERROR_BIT                  0x2000\r
185 #define HEVC_DEC_BUFFER_EMPTY_BIT               0x10000\r
186 \r
187 #define VPU_REG_EN_ENC                          14\r
188 #define VPU_REG_ENC_GATE                        2\r
189 #define VPU_REG_ENC_GATE_BIT                    (1<<4)\r
190 \r
191 #define VPU_REG_EN_DEC                          1\r
192 #define VPU_REG_DEC_GATE                        2\r
193 #define VPU_REG_DEC_GATE_BIT                    (1<<10)\r
194 #define VPU_REG_EN_PP                           0\r
195 #define VPU_REG_PP_GATE                         1\r
196 #define VPU_REG_PP_GATE_BIT                     (1<<8)\r
197 #define VPU_REG_EN_DEC_PP                       1\r
198 #define VPU_REG_DEC_PP_GATE                     61\r
199 #define VPU_REG_DEC_PP_GATE_BIT                 (1<<8)\r
200 \r
201 #if defined(CONFIG_VCODEC_MMU)\r
202 static u8 addr_tbl_vpu_h264dec[] = {\r
203         12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
204         25, 26, 27, 28, 29, 40, 41\r
205 };\r
206 \r
207 static u8 addr_tbl_vpu_vp8dec[] = {\r
208         10,12,13, 14, 18, 19, 27, 40\r
209 };\r
210 \r
211 static u8 addr_tbl_vpu_vp6dec[] = {\r
212         12, 13, 14, 18, 27, 40\r
213 };\r
214 \r
215 static u8 addr_tbl_vpu_vc1dec[] = {\r
216         12, 13, 14, 15, 16, 17, 27, 41\r
217 };\r
218 \r
219 static u8 addr_tbl_vpu_jpegdec[] = {\r
220         12, 40, 66, 67\r
221 };\r
222 \r
223 static u8 addr_tbl_vpu_defaultdec[] = {\r
224         12, 13, 14, 15, 16, 17, 40, 41\r
225 };\r
226 \r
227 static u8 addr_tbl_vpu_enc[] = {\r
228         5, 6, 7, 8, 9, 10, 11, 12, 13, 51\r
229 };\r
230 \r
231 static u8 addr_tbl_hevc_dec[] = {\r
232         4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\r
233         21, 22, 23, 24, 42, 43\r
234 };\r
235 #endif\r
236 \r
237 enum VPU_DEC_FMT {\r
238         VPU_DEC_FMT_H264,\r
239         VPU_DEC_FMT_MPEG4,\r
240         VPU_DEC_FMT_H263,\r
241         VPU_DEC_FMT_JPEG,\r
242         VPU_DEC_FMT_VC1,\r
243         VPU_DEC_FMT_MPEG2,\r
244         VPU_DEC_FMT_MPEG1,\r
245         VPU_DEC_FMT_VP6,\r
246         VPU_DEC_FMT_RV,\r
247         VPU_DEC_FMT_VP7,\r
248         VPU_DEC_FMT_VP8,\r
249         VPU_DEC_FMT_AVS,\r
250         VPU_DEC_FMT_SVC,\r
251         VPU_DEC_FMT_VC2,\r
252         VPU_DEC_FMT_MVC,\r
253         VPU_DEC_FMT_THEORA,\r
254         VPU_DEC_FMT_RES\r
255 };\r
256 \r
257 /**\r
258  * struct for process session which connect to vpu\r
259  *\r
260  * @author ChenHengming (2011-5-3)\r
261  */\r
262 typedef struct vpu_session {\r
263         VPU_CLIENT_TYPE         type;\r
264         /* a linked list of data so we can access them for debugging */\r
265         struct list_head        list_session;\r
266         /* a linked list of register data waiting for process */\r
267         struct list_head        waiting;\r
268         /* a linked list of register data in processing */\r
269         struct list_head        running;\r
270         /* a linked list of register data processed */\r
271         struct list_head        done;\r
272         wait_queue_head_t       wait;\r
273         pid_t                   pid;\r
274         atomic_t                task_running;\r
275 } vpu_session;\r
276 \r
277 /**\r
278  * struct for process register set\r
279  *\r
280  * @author ChenHengming (2011-5-4)\r
281  */\r
282 typedef struct vpu_reg {\r
283         VPU_CLIENT_TYPE         type;\r
284         VPU_FREQ                freq;\r
285         vpu_session             *session;\r
286         struct list_head        session_link;           /* link to vpu service session */\r
287         struct list_head        status_link;            /* link to register set list */\r
288         unsigned long           size;\r
289 #if defined(CONFIG_VCODEC_MMU)\r
290         struct list_head        mem_region_list;\r
291 #endif\r
292         unsigned long           *reg;\r
293 } vpu_reg;\r
294 \r
295 typedef struct vpu_device {\r
296         atomic_t                irq_count_codec;\r
297         atomic_t                irq_count_pp;\r
298         unsigned long           iobaseaddr;\r
299         unsigned int            iosize;\r
300         volatile u32            *hwregs;\r
301 } vpu_device;\r
302 \r
303 enum vcodec_device_id {\r
304         VCODEC_DEVICE_ID_VPU,\r
305         VCODEC_DEVICE_ID_HEVC\r
306 };\r
307 \r
308 struct vcodec_mem_region {\r
309         struct list_head srv_lnk;\r
310         struct list_head reg_lnk;\r
311         struct list_head session_lnk;\r
312         unsigned long iova;     /* virtual address for iommu */\r
313         unsigned long len;\r
314         struct ion_handle *hdl;\r
315 };\r
316 \r
317 typedef struct vpu_service_info {\r
318         struct wake_lock        wake_lock;\r
319         struct delayed_work     power_off_work;\r
320         struct mutex            lock;\r
321         struct list_head        waiting;                /* link to link_reg in struct vpu_reg */\r
322         struct list_head        running;                /* link to link_reg in struct vpu_reg */\r
323         struct list_head        done;                   /* link to link_reg in struct vpu_reg */\r
324         struct list_head        session;                /* link to list_session in struct vpu_session */\r
325         atomic_t                total_running;\r
326         bool                    enabled;\r
327         vpu_reg                 *reg_codec;\r
328         vpu_reg                 *reg_pproc;\r
329         vpu_reg                 *reg_resev;\r
330         VPUHwDecConfig_t        dec_config;\r
331         VPUHwEncConfig_t        enc_config;\r
332         VPU_HW_INFO_E           *hw_info;\r
333         unsigned long           reg_size;\r
334         bool                    auto_freq;\r
335         bool                    bug_dec_addr;\r
336         atomic_t                freq_status;\r
337 \r
338         struct clk              *aclk_vcodec;\r
339         struct clk              *hclk_vcodec;\r
340         struct clk              *clk_core;\r
341         struct clk              *clk_cabac;\r
342         struct clk              *pd_video;\r
343 \r
344         int                     irq_dec;\r
345         int                     irq_enc;\r
346 \r
347         vpu_device              enc_dev;\r
348         vpu_device              dec_dev;\r
349 \r
350         struct device           *dev;\r
351 \r
352         struct cdev             cdev;\r
353         dev_t                   dev_t;\r
354         struct class            *cls;\r
355         struct device           *child_dev;\r
356 \r
357         struct dentry           *debugfs_dir;\r
358         struct dentry           *debugfs_file_regs;\r
359 \r
360         u32 irq_status;\r
361 #if defined(CONFIG_VCODEC_MMU)\r
362         struct ion_client       *ion_client;\r
363         struct list_head        mem_region_list;\r
364         struct device           *mmu_dev;\r
365 #endif\r
366 \r
367         enum vcodec_device_id   dev_id;\r
368 \r
369         u32                     reserved_mode;\r
370 \r
371         struct delayed_work     simulate_work;\r
372 } vpu_service_info;\r
373 \r
374 typedef struct vpu_request\r
375 {\r
376         unsigned long *req;\r
377         unsigned long size;\r
378 } vpu_request;\r
379 \r
380 /// global variable\r
381 //static struct clk *pd_video;\r
382 static struct dentry *parent; // debugfs root directory for all device (vpu, hevc).\r
383 /* mutex for selecting operation registers of vpu or hevc */\r
384 static struct mutex g_mode_mutex;\r
385 \r
386 #ifdef CONFIG_DEBUG_FS\r
387 static int vcodec_debugfs_init(void);\r
388 static void vcodec_debugfs_exit(void);\r
389 static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent);\r
390 static int debug_vcodec_open(struct inode *inode, struct file *file);\r
391 \r
392 static const struct file_operations debug_vcodec_fops = {\r
393         .open = debug_vcodec_open,\r
394         .read = seq_read,\r
395         .llseek = seq_lseek,\r
396         .release = single_release,\r
397 };\r
398 #endif\r
399 \r
400 #define VPU_POWER_OFF_DELAY             4*HZ /* 4s */\r
401 #define VPU_TIMEOUT_DELAY               2*HZ /* 2s */\r
402 #define VPU_SIMULATE_DELAY              msecs_to_jiffies(15)\r
403 \r
404 #define BIT_VCODEC_SEL_RK3036           (1<<3)\r
405 #define BIT_VCODEC_SEL_RK312X           (1<<15)\r
406 static void vcodec_enter_mode_nolock(enum vcodec_device_id id, u32 *reserved_mode)\r
407 {\r
408         if (cpu_is_rk3036() || cpu_is_rk312x()) {\r
409                 int bits = cpu_is_rk3036() ? BIT_VCODEC_SEL_RK3036 : BIT_VCODEC_SEL_RK312X;\r
410                 void __iomem *addr = cpu_is_rk3036() ? (RK_GRF_VIRT + RK3036_GRF_SOC_CON1) : (RK_GRF_VIRT + RK312X_GRF_SOC_CON1);\r
411                 if (reserved_mode)\r
412                         *reserved_mode = readl_relaxed(addr);\r
413                 if (id == VCODEC_DEVICE_ID_HEVC)\r
414                         writel_relaxed(readl_relaxed(addr) | (bits) | (bits << 16), addr);\r
415                 else\r
416                         writel_relaxed((readl_relaxed(addr) & (~bits)) | (bits << 16), addr);\r
417         }\r
418 }\r
419 \r
420 static void vcodec_exit_mode_nolock(enum vcodec_device_id id, u32 reserved_mode)\r
421 {\r
422         if (cpu_is_rk3036() || cpu_is_rk312x()) {\r
423                 int bits = cpu_is_rk3036() ? BIT_VCODEC_SEL_RK3036 : BIT_VCODEC_SEL_RK312X;\r
424                 void __iomem *addr = cpu_is_rk3036() ? (RK_GRF_VIRT + RK3036_GRF_SOC_CON1) : (RK_GRF_VIRT + RK312X_GRF_SOC_CON1);\r
425                 writel_relaxed(reserved_mode | (bits << 16), addr);\r
426         }\r
427 }\r
428 \r
429 static void vcodec_enter_mode(enum vcodec_device_id id)\r
430 {\r
431         if (cpu_is_rk3036() || cpu_is_rk312x())\r
432                 mutex_lock(&g_mode_mutex);\r
433         vcodec_enter_mode_nolock(id, NULL);\r
434 }\r
435 \r
436 static void vcodec_exit_mode(void)\r
437 {\r
438         if (cpu_is_rk3036() || cpu_is_rk312x())\r
439                 mutex_unlock(&g_mode_mutex);\r
440 }\r
441 \r
442 static int vpu_get_clk(struct vpu_service_info *pservice)\r
443 {\r
444 #if VCODEC_CLOCK_ENABLE\r
445         do {\r
446                 pservice->aclk_vcodec   = devm_clk_get(pservice->dev, "aclk_vcodec");\r
447                 if (IS_ERR(pservice->aclk_vcodec)) {\r
448                         dev_err(pservice->dev, "failed on clk_get aclk_vcodec\n");\r
449                         break;\r
450                 }\r
451 \r
452                 pservice->hclk_vcodec   = devm_clk_get(pservice->dev, "hclk_vcodec");\r
453                 if (IS_ERR(pservice->hclk_vcodec)) {\r
454                         dev_err(pservice->dev, "failed on clk_get hclk_vcodec\n");\r
455                         break;\r
456                 }\r
457 \r
458                 if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) {\r
459                         pservice->clk_core = devm_clk_get(pservice->dev, "clk_core");\r
460                         if (IS_ERR(pservice->clk_core)) {\r
461                                 dev_err(pservice->dev, "failed on clk_get clk_core\n");\r
462                                 break;\r
463                         }\r
464 \r
465                         if (!cpu_is_rk3036() && !cpu_is_rk312x()) {\r
466                                 pservice->clk_cabac = devm_clk_get(pservice->dev, "clk_cabac");\r
467                                 if (IS_ERR(pservice->clk_cabac)) {\r
468                                         dev_err(pservice->dev, "failed on clk_get clk_cabac\n");\r
469                                         break;\r
470                                 }\r
471                         } else {\r
472                                 pservice->clk_cabac = NULL;\r
473                         }\r
474 \r
475                         if (!cpu_is_rk3036() && !cpu_is_rk312x()) {\r
476                                 pservice->pd_video = devm_clk_get(pservice->dev, "pd_hevc");\r
477                                 if (IS_ERR(pservice->pd_video)) {\r
478                                         dev_err(pservice->dev, "failed on clk_get pd_hevc\n");\r
479                                         break;\r
480                                 }\r
481                         } else {\r
482                                 pservice->pd_video = NULL;\r
483                         }\r
484                 } else {\r
485                         if (!cpu_is_rk3036() && !cpu_is_rk312x()) {\r
486                                 pservice->pd_video = devm_clk_get(pservice->dev, "pd_video");\r
487                                 if (IS_ERR(pservice->pd_video)) {\r
488                                         dev_err(pservice->dev, "failed on clk_get pd_video\n");\r
489                                         break;\r
490                                 }\r
491                         } else {\r
492                                 pservice->pd_video = NULL;\r
493                         }\r
494                 }\r
495 \r
496                 if (cpu_is_rk312x()) {\r
497                         pservice->pd_video = devm_clk_get(pservice->dev, "pd_video");\r
498                         if (IS_ERR(pservice->pd_video)) {\r
499                                 dev_err(pservice->dev, "failed on clk_get pd_video\n");\r
500                                 break;\r
501                         }\r
502                 }\r
503 \r
504                 return 0;\r
505         } while (0);\r
506 \r
507         return -1;\r
508 #else\r
509         return 0;\r
510 #endif\r
511 }\r
512 \r
513 static void vpu_put_clk(struct vpu_service_info *pservice)\r
514 {\r
515 #if VCODEC_CLOCK_ENABLE\r
516         if (pservice->pd_video) {\r
517                 devm_clk_put(pservice->dev, pservice->pd_video);\r
518         }\r
519 \r
520         if (pservice->aclk_vcodec) {\r
521                 devm_clk_put(pservice->dev, pservice->aclk_vcodec);\r
522         }\r
523 \r
524         if (pservice->hclk_vcodec) {\r
525                 devm_clk_put(pservice->dev, pservice->hclk_vcodec);\r
526         }\r
527 \r
528         if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) {\r
529                 if (pservice->clk_core) {\r
530                         devm_clk_put(pservice->dev, pservice->clk_core);\r
531                 }\r
532 \r
533                 if (pservice->clk_cabac) {\r
534                         devm_clk_put(pservice->dev, pservice->clk_cabac);\r
535                 }\r
536         }\r
537 #endif\r
538 }\r
539 \r
540 static void vpu_reset(struct vpu_service_info *pservice)\r
541 {\r
542 #if defined(CONFIG_ARCH_RK29)\r
543         clk_disable(aclk_ddr_vepu);\r
544         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);\r
545         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);\r
546         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);\r
547         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);\r
548         mdelay(10);\r
549         cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);\r
550         cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);\r
551         cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);\r
552         cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);\r
553         clk_enable(aclk_ddr_vepu);\r
554 #elif defined(CONFIG_ARCH_RK30)\r
555         pmu_set_idle_request(IDLE_REQ_VIDEO, true);\r
556         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true);\r
557         cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, true);\r
558         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true);\r
559         cru_set_soft_reset(SOFT_RST_VCODEC_AXI, true);\r
560         mdelay(1);\r
561         cru_set_soft_reset(SOFT_RST_VCODEC_AXI, false);\r
562         cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false);\r
563         cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, false);\r
564         cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false);\r
565         pmu_set_idle_request(IDLE_REQ_VIDEO, false);\r
566 #endif\r
567         pservice->reg_codec = NULL;\r
568         pservice->reg_pproc = NULL;\r
569         pservice->reg_resev = NULL;\r
570 }\r
571 \r
572 static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg);\r
573 static void vpu_service_session_clear(struct vpu_service_info *pservice, vpu_session *session)\r
574 {\r
575         vpu_reg *reg, *n;\r
576         list_for_each_entry_safe(reg, n, &session->waiting, session_link) {\r
577                 reg_deinit(pservice, reg);\r
578         }\r
579         list_for_each_entry_safe(reg, n, &session->running, session_link) {\r
580                 reg_deinit(pservice, reg);\r
581         }\r
582         list_for_each_entry_safe(reg, n, &session->done, session_link) {\r
583                 reg_deinit(pservice, reg);\r
584         }\r
585 }\r
586 \r
587 static void vpu_service_dump(struct vpu_service_info *pservice)\r
588 {\r
589         int running;\r
590         vpu_reg *reg, *reg_tmp;\r
591         vpu_session *session, *session_tmp;\r
592 \r
593         running = atomic_read(&pservice->total_running);\r
594         printk("total_running %d\n", running);\r
595 \r
596         printk("reg_codec 0x%.8x\n", (unsigned int)pservice->reg_codec);\r
597         printk("reg_pproc 0x%.8x\n", (unsigned int)pservice->reg_pproc);\r
598         printk("reg_resev 0x%.8x\n", (unsigned int)pservice->reg_resev);\r
599 \r
600         list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) {\r
601                 printk("session pid %d type %d:\n", session->pid, session->type);\r
602                 running = atomic_read(&session->task_running);\r
603                 printk("task_running %d\n", running);\r
604                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {\r
605                         printk("waiting register set 0x%.8x\n", (unsigned int)reg);\r
606                 }\r
607                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {\r
608                         printk("running register set 0x%.8x\n", (unsigned int)reg);\r
609                 }\r
610                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {\r
611                         printk("done    register set 0x%.8x\n", (unsigned int)reg);\r
612                 }\r
613         }\r
614 }\r
615 \r
616 static void vpu_service_power_off(struct vpu_service_info *pservice)\r
617 {\r
618         int total_running;\r
619         if (!pservice->enabled)\r
620                 return;\r
621 \r
622         pservice->enabled = false;\r
623         total_running = atomic_read(&pservice->total_running);\r
624         if (total_running) {\r
625                 pr_alert("alert: power off when %d task running!!\n", total_running);\r
626                 mdelay(50);\r
627                 pr_alert("alert: delay 50 ms for running task\n");\r
628                 vpu_service_dump(pservice);\r
629         }\r
630 \r
631 #if defined(CONFIG_VCODEC_MMU)\r
632         if (pservice->mmu_dev)\r
633                 iovmm_deactivate(pservice->dev);\r
634 #endif\r
635 \r
636         pr_info("%s: power off...", dev_name(pservice->dev));\r
637         udelay(10);\r
638 #if VCODEC_CLOCK_ENABLE\r
639         if (pservice->pd_video)\r
640                 clk_disable_unprepare(pservice->pd_video);\r
641         if (pservice->hclk_vcodec)\r
642                 clk_disable_unprepare(pservice->hclk_vcodec);\r
643         if (pservice->aclk_vcodec)\r
644                 clk_disable_unprepare(pservice->aclk_vcodec);\r
645         if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) {\r
646                 if (pservice->clk_core)\r
647                         clk_disable_unprepare(pservice->clk_core);\r
648                 if (pservice->clk_cabac)\r
649                         clk_disable_unprepare(pservice->clk_cabac);\r
650         }\r
651 #endif\r
652         wake_unlock(&pservice->wake_lock);\r
653         pr_info("done\n");\r
654 }\r
655 \r
656 static inline void vpu_queue_power_off_work(struct vpu_service_info *pservice)\r
657 {\r
658         queue_delayed_work(system_nrt_wq, &pservice->power_off_work, VPU_POWER_OFF_DELAY);\r
659 }\r
660 \r
661 static void vpu_power_off_work(struct work_struct *work_s)\r
662 {\r
663         struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work);\r
664         struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, power_off_work);\r
665 \r
666         if (mutex_trylock(&pservice->lock)) {\r
667                 vpu_service_power_off(pservice);\r
668                 mutex_unlock(&pservice->lock);\r
669         } else {\r
670                 /* Come back later if the device is busy... */\r
671                 vpu_queue_power_off_work(pservice);\r
672         }\r
673 }\r
674 \r
675 static void vpu_service_power_on(struct vpu_service_info *pservice)\r
676 {\r
677         static ktime_t last;\r
678         ktime_t now = ktime_get();\r
679         if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {\r
680                 cancel_delayed_work_sync(&pservice->power_off_work);\r
681                 vpu_queue_power_off_work(pservice);\r
682                 last = now;\r
683         }\r
684         if (pservice->enabled)\r
685                 return ;\r
686 \r
687         pservice->enabled = true;\r
688         printk("%s: power on\n", dev_name(pservice->dev));\r
689 \r
690 #if VCODEC_CLOCK_ENABLE\r
691         if (pservice->aclk_vcodec)\r
692                 clk_prepare_enable(pservice->aclk_vcodec);\r
693 \r
694         if (pservice->hclk_vcodec)\r
695                 clk_prepare_enable(pservice->hclk_vcodec);\r
696 \r
697         if (pservice->dev_id == VCODEC_DEVICE_ID_HEVC) {\r
698                 if (pservice->clk_core)\r
699                         clk_prepare_enable(pservice->clk_core);\r
700         if (pservice->clk_cabac)\r
701                 clk_prepare_enable(pservice->clk_cabac);\r
702         }\r
703 \r
704         if (pservice->pd_video)\r
705                 clk_prepare_enable(pservice->pd_video);\r
706 #endif\r
707 \r
708 #if defined(CONFIG_ARCH_RK319X)\r
709         /// select aclk_vepu as vcodec clock source. \r
710 #define BIT_VCODEC_SEL  (1<<7)\r
711         writel_relaxed(readl_relaxed(RK319X_GRF_BASE + GRF_SOC_CON1) |\r
712                 (BIT_VCODEC_SEL) | (BIT_VCODEC_SEL << 16),\r
713                 RK319X_GRF_BASE + GRF_SOC_CON1);\r
714 #endif\r
715 \r
716         udelay(10);\r
717         wake_lock(&pservice->wake_lock);\r
718 \r
719 #if defined(CONFIG_VCODEC_MMU)\r
720         if (pservice->mmu_dev)\r
721                 iovmm_activate(pservice->dev);\r
722 #endif\r
723 }\r
724 \r
725 static inline bool reg_check_rmvb_wmv(vpu_reg *reg)\r
726 {\r
727         unsigned long type = (reg->reg[3] & 0xF0000000) >> 28;\r
728         return ((type == 8) || (type == 4));\r
729 }\r
730 \r
731 static inline bool reg_check_interlace(vpu_reg *reg)\r
732 {\r
733         unsigned long type = (reg->reg[3] & (1 << 23));\r
734         return (type > 0);\r
735 }\r
736 \r
737 static inline enum VPU_DEC_FMT reg_check_fmt(vpu_reg *reg)\r
738 {\r
739         enum VPU_DEC_FMT type = (enum VPU_DEC_FMT)((reg->reg[3] & 0xF0000000) >> 28);\r
740         return type;\r
741 }\r
742 \r
743 static inline int reg_probe_width(vpu_reg *reg)\r
744 {\r
745         int width_in_mb = reg->reg[4] >> 23;\r
746         return width_in_mb * 16;\r
747 }\r
748 \r
749 #if defined(CONFIG_VCODEC_MMU)\r
750 static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int size, vpu_reg *reg)\r
751 {\r
752         int i;\r
753         int usr_fd = 0;\r
754         int offset = 0;\r
755 \r
756         if (tbl == NULL || size <= 0) {\r
757                 dev_err(pservice->dev, "input arguments invalidate\n");\r
758                 return -1;\r
759         }\r
760 \r
761         vpu_service_power_on(pservice);\r
762 \r
763         for (i = 0; i < size; i++) {\r
764                 usr_fd = reg->reg[tbl[i]] & 0x3FF;\r
765 \r
766                 if (tbl[i] == 41 && pservice->hw_info->hw_id != HEVC_ID &&\r
767                     (reg->type == VPU_DEC || reg->type == VPU_DEC_PP))\r
768                         /* special for vpu dec num 41 regitster */\r
769                         offset = reg->reg[tbl[i]] >> 10 << 4;\r
770                 else\r
771                         offset = reg->reg[tbl[i]] >> 10;\r
772 \r
773                 if (usr_fd != 0) {\r
774                         struct ion_handle *hdl;\r
775                         int ret;\r
776                         struct vcodec_mem_region *mem_region;\r
777 \r
778                         hdl = ion_import_dma_buf(pservice->ion_client, usr_fd);\r
779                         if (IS_ERR(hdl)) {\r
780                                 dev_err(pservice->dev, "import dma-buf from fd %d failed, reg[%d]\n", usr_fd, tbl[i]);\r
781                                 return PTR_ERR(hdl);\r
782                         }\r
783 \r
784                         mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL);\r
785 \r
786                         if (mem_region == NULL) {\r
787                                 dev_err(pservice->dev, "allocate memory for iommu memory region failed\n");\r
788                                 ion_free(pservice->ion_client, hdl);\r
789                                 return -1;\r
790                         }\r
791 \r
792                         mem_region->hdl = hdl;\r
793 \r
794                         vcodec_enter_mode(pservice->dev_id);\r
795                         ret = ion_map_iommu(pservice->dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len);\r
796                         vcodec_exit_mode();\r
797                         if (ret < 0) {\r
798                                 dev_err(pservice->dev, "ion map iommu failed\n");\r
799                                 kfree(mem_region);\r
800                                 ion_free(pservice->ion_client, hdl);\r
801                                 return ret;\r
802                         }\r
803                         reg->reg[tbl[i]] = mem_region->iova + offset;\r
804                         INIT_LIST_HEAD(&mem_region->reg_lnk);\r
805                         list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);\r
806                 }\r
807         }\r
808         return 0;\r
809 }\r
810 \r
811 static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_reg *reg)\r
812 {\r
813         VPU_HW_ID hw_id;\r
814         u8 *tbl;\r
815         int size = 0;\r
816 \r
817         hw_id = pservice->hw_info->hw_id;\r
818 \r
819         if (hw_id == HEVC_ID) {\r
820                 tbl = addr_tbl_hevc_dec;\r
821                 size = sizeof(addr_tbl_hevc_dec);\r
822         } else {\r
823                 if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {\r
824                         switch (reg_check_fmt(reg)) {\r
825                         case VPU_DEC_FMT_H264:\r
826                                 {\r
827                                         tbl = addr_tbl_vpu_h264dec;\r
828                                         size = sizeof(addr_tbl_vpu_h264dec);\r
829                                         break;\r
830                                 }\r
831                         case VPU_DEC_FMT_VP8:\r
832                         case VPU_DEC_FMT_VP7:\r
833                                 {\r
834                                         tbl = addr_tbl_vpu_vp8dec;\r
835                                         size = sizeof(addr_tbl_vpu_vp8dec);\r
836                                         break;\r
837                                 }\r
838 \r
839                         case VPU_DEC_FMT_VP6:\r
840                                 {\r
841                                         tbl = addr_tbl_vpu_vp6dec;\r
842                                         size = sizeof(addr_tbl_vpu_vp6dec);\r
843                                         break;\r
844                                 }\r
845                         case VPU_DEC_FMT_VC1:\r
846                                 {\r
847                                         tbl = addr_tbl_vpu_vc1dec;\r
848                                         size = sizeof(addr_tbl_vpu_vc1dec);\r
849                                         break;\r
850                                 }\r
851 \r
852                         case VPU_DEC_FMT_JPEG:\r
853                                 {\r
854                                         tbl = addr_tbl_vpu_jpegdec;\r
855                                         size = sizeof(addr_tbl_vpu_jpegdec);\r
856                                         break;\r
857                                 }\r
858                         default:\r
859                                 tbl = addr_tbl_vpu_defaultdec;\r
860                                 size = sizeof(addr_tbl_vpu_defaultdec);\r
861                                 break;\r
862                         }\r
863                 } else if (reg->type == VPU_ENC) {\r
864                         tbl = addr_tbl_vpu_enc;\r
865                         size = sizeof(addr_tbl_vpu_enc);\r
866                 }\r
867         }\r
868 \r
869         if (size != 0) {\r
870                 return vcodec_bufid_to_iova(pservice, tbl, size, reg);\r
871         } else {\r
872                 return -1;\r
873         }\r
874 }\r
875 #endif\r
876 \r
877 static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session, void __user *src, unsigned long size)\r
878 {\r
879         vpu_reg *reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);\r
880         if (NULL == reg) {\r
881                 pr_err("error: kmalloc fail in reg_init\n");\r
882                 return NULL;\r
883         }\r
884 \r
885         if (size > pservice->reg_size) {\r
886                 printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
887                 size = pservice->reg_size;\r
888         }\r
889         reg->session = session;\r
890         reg->type = session->type;\r
891         reg->size = size;\r
892         reg->freq = VPU_FREQ_DEFAULT;\r
893         reg->reg = (unsigned long *)&reg[1];\r
894         INIT_LIST_HEAD(&reg->session_link);\r
895         INIT_LIST_HEAD(&reg->status_link);\r
896 \r
897 #if defined(CONFIG_VCODEC_MMU)\r
898         if (pservice->mmu_dev)\r
899                 INIT_LIST_HEAD(&reg->mem_region_list);\r
900 #endif\r
901 \r
902         if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {\r
903                 pr_err("error: copy_from_user failed in reg_init\n");\r
904                 kfree(reg);\r
905                 return NULL;\r
906         }\r
907 \r
908 #if defined(CONFIG_VCODEC_MMU)\r
909         if (pservice->mmu_dev && 0 > vcodec_reg_address_translate(pservice, reg)) {\r
910                 pr_err("error: translate reg address failed\n");\r
911                 kfree(reg);\r
912                 return NULL;\r
913         }\r
914 #endif\r
915 \r
916         mutex_lock(&pservice->lock);\r
917         list_add_tail(&reg->status_link, &pservice->waiting);\r
918         list_add_tail(&reg->session_link, &session->waiting);\r
919         mutex_unlock(&pservice->lock);\r
920 \r
921         if (pservice->auto_freq) {\r
922                 if (!soc_is_rk2928g()) {\r
923                         if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {\r
924                                 if (reg_check_rmvb_wmv(reg)) {\r
925                                         reg->freq = VPU_FREQ_200M;\r
926                                 } else if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {\r
927                                         if (reg_probe_width(reg) > 3200) {\r
928                                                 // raise frequency for 4k avc.\r
929                                                 reg->freq = VPU_FREQ_500M;\r
930                                         }\r
931                                 } else {\r
932                                         if (reg_check_interlace(reg)) {\r
933                                                 reg->freq = VPU_FREQ_400M;\r
934                                         }\r
935                                 }\r
936                         }\r
937                         if (reg->type == VPU_PP) {\r
938                                 reg->freq = VPU_FREQ_400M;\r
939                         }\r
940                 }\r
941         }\r
942 \r
943         return reg;\r
944 }\r
945 \r
946 static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg)\r
947 {\r
948 #if defined(CONFIG_VCODEC_MMU)\r
949         struct vcodec_mem_region *mem_region = NULL, *n;\r
950 #endif\r
951 \r
952         list_del_init(&reg->session_link);\r
953         list_del_init(&reg->status_link);\r
954         if (reg == pservice->reg_codec)\r
955                 pservice->reg_codec = NULL;\r
956         if (reg == pservice->reg_pproc)\r
957                 pservice->reg_pproc = NULL;\r
958 \r
959 #if defined(CONFIG_VCODEC_MMU)\r
960         // release memory region attach to this registers table.\r
961         if (pservice->mmu_dev) {\r
962                 list_for_each_entry_safe(mem_region, n, &reg->mem_region_list, reg_lnk) {\r
963                         /* do not unmap iommu manually,\r
964                            unmap will proccess when memory release */\r
965                         /*vcodec_enter_mode(pservice->dev_id);\r
966                         ion_unmap_iommu(pservice->dev,\r
967                                         pservice->ion_client,\r
968                                         mem_region->hdl);\r
969                         vcodec_exit_mode();*/\r
970                         ion_free(pservice->ion_client, mem_region->hdl);\r
971                         list_del_init(&mem_region->reg_lnk);\r
972                         kfree(mem_region);\r
973                 }\r
974         }\r
975 #endif\r
976 \r
977         kfree(reg);\r
978 }\r
979 \r
980 static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg)\r
981 {\r
982         list_del_init(&reg->status_link);\r
983         list_add_tail(&reg->status_link, &pservice->running);\r
984 \r
985         list_del_init(&reg->session_link);\r
986         list_add_tail(&reg->session_link, &reg->session->running);\r
987 }\r
988 \r
989 static void reg_copy_from_hw(struct vpu_service_info *pservice, vpu_reg *reg, volatile u32 *src, u32 count)\r
990 {\r
991         int i;\r
992         u32 *dst = (u32 *)&reg->reg[0];\r
993 \r
994         for (i = 0; i < count; i++)\r
995                 *dst++ = *src++;\r
996 }\r
997 \r
998 static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg)\r
999 {\r
1000         int irq_reg = -1;\r
1001         list_del_init(&reg->status_link);\r
1002         list_add_tail(&reg->status_link, &pservice->done);\r
1003 \r
1004         list_del_init(&reg->session_link);\r
1005         list_add_tail(&reg->session_link, &reg->session->done);\r
1006 \r
1007         vcodec_enter_mode(pservice->dev_id);\r
1008         switch (reg->type) {\r
1009         case VPU_ENC : {\r
1010                 pservice->reg_codec = NULL;\r
1011                 reg_copy_from_hw(pservice, reg, pservice->enc_dev.hwregs, pservice->hw_info->enc_reg_num);\r
1012                 irq_reg = ENC_INTERRUPT_REGISTER;\r
1013                 break;\r
1014         }\r
1015         case VPU_DEC : {\r
1016                 int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC;\r
1017                 pservice->reg_codec = NULL;\r
1018                 reg_copy_from_hw(pservice, reg, pservice->dec_dev.hwregs, reg_len);\r
1019                 irq_reg = DEC_INTERRUPT_REGISTER;\r
1020                 break;\r
1021         }\r
1022         case VPU_PP : {\r
1023                 pservice->reg_pproc = NULL;\r
1024                 reg_copy_from_hw(pservice, reg, pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER, REG_NUM_9190_PP);\r
1025                 pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;\r
1026                 break;\r
1027         }\r
1028         case VPU_DEC_PP : {\r
1029                 pservice->reg_codec = NULL;\r
1030                 pservice->reg_pproc = NULL;\r
1031                 reg_copy_from_hw(pservice, reg, pservice->dec_dev.hwregs, REG_NUM_9190_DEC_PP);\r
1032                 pservice->dec_dev.hwregs[PP_INTERRUPT_REGISTER] = 0;\r
1033                 break;\r
1034         }\r
1035         default : {\r
1036                 pr_err("error: copy reg from hw with unknown type %d\n", reg->type);\r
1037                 break;\r
1038         }\r
1039         }\r
1040         vcodec_exit_mode();\r
1041 \r
1042         if (irq_reg != -1) {\r
1043                 reg->reg[irq_reg] = pservice->irq_status;\r
1044         }\r
1045 \r
1046         atomic_sub(1, &reg->session->task_running);\r
1047         atomic_sub(1, &pservice->total_running);\r
1048         wake_up(&reg->session->wait);\r
1049 }\r
1050 \r
1051 static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg)\r
1052 {\r
1053         VPU_FREQ curr = atomic_read(&pservice->freq_status);\r
1054         if (curr == reg->freq) {\r
1055                 return ;\r
1056         }\r
1057         atomic_set(&pservice->freq_status, reg->freq);\r
1058         switch (reg->freq) {\r
1059         case VPU_FREQ_200M : {\r
1060                 clk_set_rate(pservice->aclk_vcodec, 200*MHZ);\r
1061                 //printk("default: 200M\n");\r
1062         } break;\r
1063         case VPU_FREQ_266M : {\r
1064                 clk_set_rate(pservice->aclk_vcodec, 266*MHZ);\r
1065                 //printk("default: 266M\n");\r
1066         } break;\r
1067         case VPU_FREQ_300M : {\r
1068                 clk_set_rate(pservice->aclk_vcodec, 300*MHZ);\r
1069                 //printk("default: 300M\n");\r
1070         } break;\r
1071         case VPU_FREQ_400M : {\r
1072                 clk_set_rate(pservice->aclk_vcodec, 400*MHZ);\r
1073                 //printk("default: 400M\n");\r
1074         } break;\r
1075         case VPU_FREQ_500M : {\r
1076                 clk_set_rate(pservice->aclk_vcodec, 500*MHZ);\r
1077         } break;\r
1078         case VPU_FREQ_600M : {\r
1079                 clk_set_rate(pservice->aclk_vcodec, 600*MHZ);\r
1080         } break;\r
1081         default : {\r
1082                 if (soc_is_rk2928g()) {\r
1083                         clk_set_rate(pservice->aclk_vcodec, 400*MHZ);\r
1084                 } else {\r
1085                         clk_set_rate(pservice->aclk_vcodec, 300*MHZ);\r
1086                 }\r
1087                 //printk("default: 300M\n");\r
1088         } break;\r
1089         }\r
1090 }\r
1091 \r
1092 #if HEVC_SIM_ENABLE\r
1093 static void simulate_start(struct vpu_service_info *pservice);\r
1094 #endif\r
1095 static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg)\r
1096 {\r
1097         int i;\r
1098         u32 *src = (u32 *)&reg->reg[0];\r
1099         atomic_add(1, &pservice->total_running);\r
1100         atomic_add(1, &reg->session->task_running);\r
1101         if (pservice->auto_freq) {\r
1102                 vpu_service_set_freq(pservice, reg);\r
1103         }\r
1104 \r
1105         vcodec_enter_mode(pservice->dev_id);\r
1106 \r
1107         switch (reg->type) {\r
1108         case VPU_ENC : {\r
1109                 int enc_count = pservice->hw_info->enc_reg_num;\r
1110                 u32 *dst = (u32 *)pservice->enc_dev.hwregs;\r
1111 \r
1112                 pservice->reg_codec = reg;\r
1113 \r
1114                 dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;\r
1115 \r
1116                 for (i = 0; i < VPU_REG_EN_ENC; i++)\r
1117                         dst[i] = src[i];\r
1118 \r
1119                 for (i = VPU_REG_EN_ENC + 1; i < enc_count; i++)\r
1120                         dst[i] = src[i];\r
1121 \r
1122                 dsb();\r
1123 \r
1124                 dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;\r
1125                 dst[VPU_REG_EN_ENC]   = src[VPU_REG_EN_ENC];\r
1126 \r
1127 #if VPU_SERVICE_SHOW_TIME\r
1128                 do_gettimeofday(&enc_start);\r
1129 #endif\r
1130 \r
1131         } break;\r
1132         case VPU_DEC : {\r
1133                 u32 *dst = (u32 *)pservice->dec_dev.hwregs;\r
1134 \r
1135                 pservice->reg_codec = reg;\r
1136 \r
1137                 if (pservice->hw_info->hw_id != HEVC_ID) {\r
1138                         for (i = REG_NUM_9190_DEC - 1; i > VPU_REG_DEC_GATE; i--)\r
1139                                 dst[i] = src[i];\r
1140                 } else {\r
1141                         for (i = REG_NUM_HEVC_DEC - 1; i > VPU_REG_EN_DEC; i--) {\r
1142                                 dst[i] = src[i];\r
1143                         }\r
1144                 }\r
1145 \r
1146                 dsb();\r
1147 \r
1148                 if (pservice->hw_info->hw_id != HEVC_ID) {\r
1149                         dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;\r
1150                         dst[VPU_REG_EN_DEC]   = src[VPU_REG_EN_DEC];\r
1151                 } else {\r
1152                         dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC];\r
1153                 }\r
1154 \r
1155                 dsb();\r
1156                 dmb();\r
1157 \r
1158 #if VPU_SERVICE_SHOW_TIME\r
1159                 do_gettimeofday(&dec_start);\r
1160 #endif\r
1161 \r
1162         } break;\r
1163         case VPU_PP : {\r
1164                 u32 *dst = (u32 *)pservice->dec_dev.hwregs + PP_INTERRUPT_REGISTER;\r
1165                 pservice->reg_pproc = reg;\r
1166 \r
1167                 dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;\r
1168 \r
1169                 for (i = VPU_REG_PP_GATE + 1; i < REG_NUM_9190_PP; i++)\r
1170                         dst[i] = src[i];\r
1171 \r
1172                 dsb();\r
1173 \r
1174                 dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];\r
1175 \r
1176 #if VPU_SERVICE_SHOW_TIME\r
1177                 do_gettimeofday(&pp_start);\r
1178 #endif\r
1179 \r
1180         } break;\r
1181         case VPU_DEC_PP : {\r
1182                 u32 *dst = (u32 *)pservice->dec_dev.hwregs;\r
1183                 pservice->reg_codec = reg;\r
1184                 pservice->reg_pproc = reg;\r
1185 \r
1186                 for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_9190_DEC_PP; i++)\r
1187                         dst[i] = src[i];\r
1188 \r
1189                 dst[VPU_REG_EN_DEC_PP]   = src[VPU_REG_EN_DEC_PP] | 0x2;\r
1190                 dsb();\r
1191 \r
1192                 dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;\r
1193                 dst[VPU_REG_DEC_GATE]    = src[VPU_REG_DEC_GATE]    | VPU_REG_DEC_GATE_BIT;\r
1194                 dst[VPU_REG_EN_DEC]      = src[VPU_REG_EN_DEC];\r
1195 \r
1196 #if VPU_SERVICE_SHOW_TIME\r
1197                 do_gettimeofday(&dec_start);\r
1198 #endif\r
1199 \r
1200         } break;\r
1201         default : {\r
1202                 pr_err("error: unsupport session type %d", reg->type);\r
1203                 atomic_sub(1, &pservice->total_running);\r
1204                 atomic_sub(1, &reg->session->task_running);\r
1205                 break;\r
1206         }\r
1207         }\r
1208 \r
1209         vcodec_exit_mode();\r
1210 \r
1211 #if HEVC_SIM_ENABLE\r
1212         if (pservice->hw_info->hw_id == HEVC_ID) {\r
1213                 simulate_start(pservice);\r
1214         }\r
1215 #endif\r
1216 }\r
1217 \r
1218 static void try_set_reg(struct vpu_service_info *pservice)\r
1219 {\r
1220         // first get reg from reg list\r
1221         if (!list_empty(&pservice->waiting)) {\r
1222                 int can_set = 0;\r
1223                 vpu_reg *reg = list_entry(pservice->waiting.next, vpu_reg, status_link);\r
1224 \r
1225                 vpu_service_power_on(pservice);\r
1226 \r
1227                 switch (reg->type) {\r
1228                 case VPU_ENC : {\r
1229                         if ((NULL == pservice->reg_codec) &&  (NULL == pservice->reg_pproc))\r
1230                                 can_set = 1;\r
1231                 } break;\r
1232                 case VPU_DEC : {\r
1233                         if (NULL == pservice->reg_codec)\r
1234                                 can_set = 1;\r
1235                         if (pservice->auto_freq && (NULL != pservice->reg_pproc)) {\r
1236                                 can_set = 0;\r
1237                         }\r
1238                 } break;\r
1239                 case VPU_PP : {\r
1240                         if (NULL == pservice->reg_codec) {\r
1241                                 if (NULL == pservice->reg_pproc)\r
1242                                         can_set = 1;\r
1243                         } else {\r
1244                                 if ((VPU_DEC == pservice->reg_codec->type) && (NULL == pservice->reg_pproc))\r
1245                                         can_set = 1;\r
1246                                 // can not charge frequency when vpu is working\r
1247                                 if (pservice->auto_freq) {\r
1248                                         can_set = 0;\r
1249                                 }\r
1250                         }\r
1251                 } break;\r
1252                 case VPU_DEC_PP : {\r
1253                         if ((NULL == pservice->reg_codec) && (NULL == pservice->reg_pproc))\r
1254                                 can_set = 1;\r
1255                         } break;\r
1256                 default : {\r
1257                         printk("undefined reg type %d\n", reg->type);\r
1258                 } break;\r
1259                 }\r
1260                 if (can_set) {\r
1261                         reg_from_wait_to_run(pservice, reg);\r
1262                         reg_copy_to_hw(pservice, reg);\r
1263                 }\r
1264         }\r
1265 }\r
1266 \r
1267 static int return_reg(struct vpu_service_info *pservice, vpu_reg *reg, u32 __user *dst)\r
1268 {\r
1269         int ret = 0;\r
1270         switch (reg->type) {\r
1271         case VPU_ENC : {\r
1272                 if (copy_to_user(dst, &reg->reg[0], pservice->hw_info->enc_io_size))\r
1273                         ret = -EFAULT;\r
1274                 break;\r
1275         }\r
1276         case VPU_DEC : {\r
1277                 int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC;\r
1278                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(reg_len)))\r
1279                         ret = -EFAULT;\r
1280                 break;\r
1281         }\r
1282         case VPU_PP : {\r
1283                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_PP)))\r
1284                         ret = -EFAULT;\r
1285                 break;\r
1286         }\r
1287         case VPU_DEC_PP : {\r
1288                 if (copy_to_user(dst, &reg->reg[0], SIZE_REG(REG_NUM_9190_DEC_PP)))\r
1289                         ret = -EFAULT;\r
1290                 break;\r
1291         }\r
1292         default : {\r
1293                 ret = -EFAULT;\r
1294                 pr_err("error: copy reg to user with unknown type %d\n", reg->type);\r
1295                 break;\r
1296         }\r
1297         }\r
1298         reg_deinit(pservice, reg);\r
1299         return ret;\r
1300 }\r
1301 \r
1302 static long vpu_service_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
1303 {\r
1304     struct vpu_service_info *pservice = container_of(filp->f_dentry->d_inode->i_cdev, struct vpu_service_info, cdev);\r
1305         vpu_session *session = (vpu_session *)filp->private_data;\r
1306         if (NULL == session) {\r
1307                 return -EINVAL;\r
1308         }\r
1309 \r
1310         switch (cmd) {\r
1311         case VPU_IOC_SET_CLIENT_TYPE : {\r
1312                 session->type = (VPU_CLIENT_TYPE)arg;\r
1313                 break;\r
1314         }\r
1315         case VPU_IOC_GET_HW_FUSE_STATUS : {\r
1316                 vpu_request req;\r
1317                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
1318                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_from_user failed\n");\r
1319                         return -EFAULT;\r
1320                 } else {\r
1321                         if (VPU_ENC != session->type) {\r
1322                                 if (copy_to_user((void __user *)req.req, &pservice->dec_config, sizeof(VPUHwDecConfig_t))) {\r
1323                                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);\r
1324                                         return -EFAULT;\r
1325                                 }\r
1326                         } else {\r
1327                                 if (copy_to_user((void __user *)req.req, &pservice->enc_config, sizeof(VPUHwEncConfig_t))) {\r
1328                                         pr_err("error: VPU_IOC_GET_HW_FUSE_STATUS copy_to_user failed type %d\n", session->type);\r
1329                                         return -EFAULT;\r
1330                                 }\r
1331                         }\r
1332                 }\r
1333 \r
1334                 break;\r
1335         }\r
1336         case VPU_IOC_SET_REG : {\r
1337                 vpu_request req;\r
1338                 vpu_reg *reg;\r
1339                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
1340                         pr_err("error: VPU_IOC_SET_REG copy_from_user failed\n");\r
1341                         return -EFAULT;\r
1342                 }\r
1343                 reg = reg_init(pservice, session, (void __user *)req.req, req.size);\r
1344                 if (NULL == reg) {\r
1345                         return -EFAULT;\r
1346                 } else {\r
1347                         mutex_lock(&pservice->lock);\r
1348                         try_set_reg(pservice);\r
1349                         mutex_unlock(&pservice->lock);\r
1350                 }\r
1351 \r
1352                 break;\r
1353         }\r
1354         case VPU_IOC_GET_REG : {\r
1355                 vpu_request req;\r
1356                 vpu_reg *reg;\r
1357                 if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {\r
1358                         pr_err("error: VPU_IOC_GET_REG copy_from_user failed\n");\r
1359                         return -EFAULT;\r
1360                 } else {\r
1361                         int ret = wait_event_timeout(session->wait, !list_empty(&session->done), VPU_TIMEOUT_DELAY);\r
1362                         if (!list_empty(&session->done)) {\r
1363                                 if (ret < 0) {\r
1364                                         pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session->pid, ret);\r
1365                                 }\r
1366                                 ret = 0;\r
1367                         } else {\r
1368                                 if (unlikely(ret < 0)) {\r
1369                                         pr_err("error: pid %d wait task ret %d\n", session->pid, ret);\r
1370                                 } else if (0 == ret) {\r
1371                                         pr_err("error: pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running));\r
1372                                         ret = -ETIMEDOUT;\r
1373                                 }\r
1374                         }\r
1375                         if (ret < 0) {\r
1376                                 int task_running = atomic_read(&session->task_running);\r
1377                                 mutex_lock(&pservice->lock);\r
1378                                 vpu_service_dump(pservice);\r
1379                                 if (task_running) {\r
1380                                         atomic_set(&session->task_running, 0);\r
1381                                         atomic_sub(task_running, &pservice->total_running);\r
1382                                         printk("%d task is running but not return, reset hardware...", task_running);\r
1383                                         vpu_reset(pservice);\r
1384                                         printk("done\n");\r
1385                                 }\r
1386                                 vpu_service_session_clear(pservice, session);\r
1387                                 mutex_unlock(&pservice->lock);\r
1388                                 return ret;\r
1389                         }\r
1390                 }\r
1391                 mutex_lock(&pservice->lock);\r
1392                 reg = list_entry(session->done.next, vpu_reg, session_link);\r
1393                 return_reg(pservice, reg, (u32 __user *)req.req);\r
1394                 mutex_unlock(&pservice->lock);\r
1395                 break;\r
1396         }\r
1397         case VPU_IOC_PROBE_IOMMU_STATUS: {\r
1398                 int iommu_enable = 0;\r
1399 \r
1400 #if defined(CONFIG_VCODEC_MMU)\r
1401                 iommu_enable = pservice->mmu_dev ? 1 : 0;\r
1402 #endif\r
1403 \r
1404                 if (copy_to_user((void __user *)arg, &iommu_enable, sizeof(int))) {\r
1405                         pr_err("error: VPU_IOC_PROBE_IOMMU_STATUS copy_to_user failed\n");\r
1406                         return -EFAULT;\r
1407                 }\r
1408                 break;\r
1409         }\r
1410         default : {\r
1411                 pr_err("error: unknow vpu service ioctl cmd %x\n", cmd);\r
1412                 break;\r
1413         }\r
1414         }\r
1415 \r
1416         return 0;\r
1417 }\r
1418 \r
1419 static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr)\r
1420 {\r
1421         int ret = -EINVAL, i = 0;\r
1422         volatile u32 *tmp = (volatile u32 *)ioremap_nocache(hw_addr, 0x4);\r
1423         u32 enc_id = *tmp;\r
1424 \r
1425 #if HEVC_SIM_ENABLE\r
1426         /// temporary, hevc driver test.\r
1427         if (strncmp(dev_name(p->dev), "hevc_service", strlen("hevc_service")) == 0) {\r
1428                 p->hw_info = &vpu_hw_set[2];\r
1429                 return 0;\r
1430         }\r
1431 #endif\r
1432         enc_id = (enc_id >> 16) & 0xFFFF;\r
1433         pr_info("checking hw id %x\n", enc_id);\r
1434         p->hw_info = NULL;\r
1435         for (i = 0; i < ARRAY_SIZE(vpu_hw_set); i++) {\r
1436                 if (enc_id == vpu_hw_set[i].hw_id) {\r
1437                         p->hw_info = &vpu_hw_set[i];\r
1438                         ret = 0;\r
1439                         break;\r
1440                 }\r
1441         }\r
1442         iounmap((void *)tmp);\r
1443         return ret;\r
1444 }\r
1445 \r
1446 static int vpu_service_open(struct inode *inode, struct file *filp)\r
1447 {\r
1448         struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev);\r
1449         vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL);\r
1450         if (NULL == session) {\r
1451                 pr_err("error: unable to allocate memory for vpu_session.");\r
1452                 return -ENOMEM;\r
1453         }\r
1454 \r
1455         session->type   = VPU_TYPE_BUTT;\r
1456         session->pid    = current->pid;\r
1457         INIT_LIST_HEAD(&session->waiting);\r
1458         INIT_LIST_HEAD(&session->running);\r
1459         INIT_LIST_HEAD(&session->done);\r
1460         INIT_LIST_HEAD(&session->list_session);\r
1461         init_waitqueue_head(&session->wait);\r
1462         atomic_set(&session->task_running, 0);\r
1463         mutex_lock(&pservice->lock);\r
1464         list_add_tail(&session->list_session, &pservice->session);\r
1465         filp->private_data = (void *)session;\r
1466         mutex_unlock(&pservice->lock);\r
1467 \r
1468         pr_debug("dev opened\n");\r
1469         return nonseekable_open(inode, filp);\r
1470 }\r
1471 \r
1472 static int vpu_service_release(struct inode *inode, struct file *filp)\r
1473 {\r
1474         struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev);\r
1475         int task_running;\r
1476         vpu_session *session = (vpu_session *)filp->private_data;\r
1477         if (NULL == session)\r
1478                 return -EINVAL;\r
1479 \r
1480         task_running = atomic_read(&session->task_running);\r
1481         if (task_running) {\r
1482                 pr_err("error: vpu_service session %d still has %d task running when closing\n", session->pid, task_running);\r
1483                 msleep(50);\r
1484         }\r
1485         wake_up(&session->wait);\r
1486 \r
1487         mutex_lock(&pservice->lock);\r
1488         /* remove this filp from the asynchronusly notified filp's */\r
1489         list_del_init(&session->list_session);\r
1490         vpu_service_session_clear(pservice, session);\r
1491         kfree(session);\r
1492         filp->private_data = NULL;\r
1493         mutex_unlock(&pservice->lock);\r
1494 \r
1495         pr_debug("dev closed\n");\r
1496         return 0;\r
1497 }\r
1498 \r
1499 static const struct file_operations vpu_service_fops = {\r
1500         .unlocked_ioctl = vpu_service_ioctl,\r
1501         .open           = vpu_service_open,\r
1502         .release        = vpu_service_release,\r
1503         //.fasync       = vpu_service_fasync,\r
1504 };\r
1505 \r
1506 static irqreturn_t vdpu_irq(int irq, void *dev_id);\r
1507 static irqreturn_t vdpu_isr(int irq, void *dev_id);\r
1508 static irqreturn_t vepu_irq(int irq, void *dev_id);\r
1509 static irqreturn_t vepu_isr(int irq, void *dev_id);\r
1510 static void get_hw_info(struct vpu_service_info *pservice);\r
1511 \r
1512 #if HEVC_SIM_ENABLE\r
1513 static void simulate_work(struct work_struct *work_s)\r
1514 {\r
1515         struct delayed_work *dlwork = container_of(work_s, struct delayed_work, work);\r
1516         struct vpu_service_info *pservice = container_of(dlwork, struct vpu_service_info, simulate_work);\r
1517         vpu_device *dev = &pservice->dec_dev;\r
1518 \r
1519         if (!list_empty(&pservice->running)) {\r
1520                 atomic_add(1, &dev->irq_count_codec);\r
1521                 vdpu_isr(0, (void*)pservice);\r
1522         } else {\r
1523                 //simulate_start(pservice);\r
1524                 pr_err("empty running queue\n");\r
1525         }\r
1526 }\r
1527 \r
1528 static void simulate_init(struct vpu_service_info *pservice)\r
1529 {\r
1530         INIT_DELAYED_WORK(&pservice->simulate_work, simulate_work);\r
1531 }\r
1532 \r
1533 static void simulate_start(struct vpu_service_info *pservice)\r
1534 {\r
1535         cancel_delayed_work_sync(&pservice->power_off_work);\r
1536         queue_delayed_work(system_nrt_wq, &pservice->simulate_work, VPU_SIMULATE_DELAY);\r
1537 }\r
1538 #endif\r
1539 \r
1540 #if HEVC_TEST_ENABLE\r
1541 static int hevc_test_case0(vpu_service_info *pservice);\r
1542 #endif\r
1543 #if defined(CONFIG_ION_ROCKCHIP)\r
1544 extern struct ion_client *rockchip_ion_client_create(const char * name);\r
1545 #endif\r
1546 static int vcodec_probe(struct platform_device *pdev)\r
1547 {\r
1548         int ret = 0;\r
1549         struct resource *res = NULL;\r
1550         struct device *dev = &pdev->dev;\r
1551         void __iomem *regs = NULL;\r
1552         struct device_node *np = pdev->dev.of_node;\r
1553         struct vpu_service_info *pservice = devm_kzalloc(dev, sizeof(struct vpu_service_info), GFP_KERNEL);\r
1554         char *prop = (char*)dev_name(dev);\r
1555 #if defined(CONFIG_VCODEC_MMU)\r
1556         u32 iommu_en = 0;\r
1557         char mmu_dev_dts_name[40];\r
1558         of_property_read_u32(np, "iommu_enabled", &iommu_en);\r
1559 #endif\r
1560 \r
1561         pr_info("probe device %s\n", dev_name(dev));\r
1562 \r
1563         of_property_read_string(np, "name", (const char**)&prop);\r
1564         dev_set_name(dev, prop);\r
1565 \r
1566         if (strcmp(dev_name(dev), "hevc_service") == 0) {\r
1567                 pservice->dev_id = VCODEC_DEVICE_ID_HEVC;\r
1568         } else if (strcmp(dev_name(dev), "vpu_service") == 0) {\r
1569                 pservice->dev_id = VCODEC_DEVICE_ID_VPU;\r
1570         } else {\r
1571                 dev_err(dev, "Unknown device %s to probe\n", dev_name(dev));\r
1572                 return -1;\r
1573         }\r
1574 \r
1575         mutex_init(&g_mode_mutex);\r
1576         vcodec_enter_mode(pservice->dev_id);\r
1577 \r
1578         wake_lock_init(&pservice->wake_lock, WAKE_LOCK_SUSPEND, "vpu");\r
1579         INIT_LIST_HEAD(&pservice->waiting);\r
1580         INIT_LIST_HEAD(&pservice->running);\r
1581         INIT_LIST_HEAD(&pservice->done);\r
1582         INIT_LIST_HEAD(&pservice->session);\r
1583         mutex_init(&pservice->lock);\r
1584         pservice->reg_codec     = NULL;\r
1585         pservice->reg_pproc     = NULL;\r
1586         atomic_set(&pservice->total_running, 0);\r
1587         pservice->enabled = false;\r
1588 #if defined(CONFIG_VCODEC_MMU)\r
1589         pservice->mmu_dev = NULL;\r
1590 #endif\r
1591         pservice->dev = dev;\r
1592 \r
1593         if (0 > vpu_get_clk(pservice))\r
1594                 goto err;\r
1595 \r
1596         INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);\r
1597 \r
1598         vpu_service_power_on(pservice);\r
1599 \r
1600         mdelay(1);\r
1601 \r
1602         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
1603 \r
1604         res->flags &= ~IORESOURCE_CACHEABLE;\r
1605 \r
1606         regs = devm_ioremap_resource(pservice->dev, res);\r
1607         if (IS_ERR(regs)) {\r
1608                 ret = PTR_ERR(regs);\r
1609                 goto err;\r
1610         }\r
1611 \r
1612         {\r
1613                 u32 offset = res->start;\r
1614                 if (cpu_is_rk3036()) {\r
1615                         if (pservice->dev_id == VCODEC_DEVICE_ID_VPU)\r
1616                                 offset += 0x400;\r
1617                 }\r
1618                 ret = vpu_service_check_hw(pservice, offset);\r
1619                 if (ret < 0) {\r
1620                         pr_err("error: hw info check faild\n");\r
1621                         goto err;\r
1622                 }\r
1623         }\r
1624 \r
1625         /// define regs address.\r
1626         pservice->dec_dev.iobaseaddr = res->start + pservice->hw_info->dec_offset;\r
1627         pservice->dec_dev.iosize     = pservice->hw_info->dec_io_size;\r
1628 \r
1629         pservice->dec_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->dec_offset);\r
1630 \r
1631         pservice->reg_size   = pservice->dec_dev.iosize;\r
1632 \r
1633         if (pservice->hw_info->hw_id != HEVC_ID && !cpu_is_rk3036()) {\r
1634                 pservice->enc_dev.iobaseaddr = res->start + pservice->hw_info->enc_offset;\r
1635                 pservice->enc_dev.iosize     = pservice->hw_info->enc_io_size;\r
1636 \r
1637                 pservice->reg_size = pservice->reg_size > pservice->enc_dev.iosize ? pservice->reg_size : pservice->enc_dev.iosize;\r
1638 \r
1639                 pservice->enc_dev.hwregs = (volatile u32 *)((u8 *)regs + pservice->hw_info->enc_offset);\r
1640 \r
1641                 pservice->irq_enc = platform_get_irq_byname(pdev, "irq_enc");\r
1642                 if (pservice->irq_enc < 0) {\r
1643                         dev_err(pservice->dev, "cannot find IRQ encoder\n");\r
1644                         ret = -ENXIO;\r
1645                         goto err;\r
1646                 }\r
1647 \r
1648                 ret = devm_request_threaded_irq(pservice->dev, pservice->irq_enc, vepu_irq, vepu_isr, 0, dev_name(pservice->dev), (void *)pservice);\r
1649                 if (ret) {\r
1650                         dev_err(pservice->dev, "error: can't request vepu irq %d\n", pservice->irq_enc);\r
1651                         goto err;\r
1652                 }\r
1653         }\r
1654 \r
1655         pservice->irq_dec = platform_get_irq_byname(pdev, "irq_dec");\r
1656         if (pservice->irq_dec < 0) {\r
1657                 dev_err(pservice->dev, "cannot find IRQ decoder\n");\r
1658                 ret = -ENXIO;\r
1659                 goto err;\r
1660         }\r
1661 \r
1662         /* get the IRQ line */\r
1663         ret = devm_request_threaded_irq(pservice->dev, pservice->irq_dec, vdpu_irq, vdpu_isr, 0, dev_name(pservice->dev), (void *)pservice);\r
1664         if (ret) {\r
1665                 dev_err(pservice->dev, "error: can't request vdpu irq %d\n", pservice->irq_dec);\r
1666                 goto err;\r
1667         }\r
1668 \r
1669         atomic_set(&pservice->dec_dev.irq_count_codec, 0);\r
1670         atomic_set(&pservice->dec_dev.irq_count_pp, 0);\r
1671         atomic_set(&pservice->enc_dev.irq_count_codec, 0);\r
1672         atomic_set(&pservice->enc_dev.irq_count_pp, 0);\r
1673 \r
1674         /// create device\r
1675         ret = alloc_chrdev_region(&pservice->dev_t, 0, 1, dev_name(dev));\r
1676         if (ret) {\r
1677                 dev_err(dev, "alloc dev_t failed\n");\r
1678                 goto err;\r
1679         }\r
1680 \r
1681         cdev_init(&pservice->cdev, &vpu_service_fops);\r
1682 \r
1683         pservice->cdev.owner = THIS_MODULE;\r
1684         pservice->cdev.ops = &vpu_service_fops;\r
1685 \r
1686         ret = cdev_add(&pservice->cdev, pservice->dev_t, 1);\r
1687 \r
1688         if (ret) {\r
1689                 dev_err(dev, "add dev_t failed\n");\r
1690                 goto err;\r
1691         }\r
1692 \r
1693         pservice->cls = class_create(THIS_MODULE, dev_name(dev));\r
1694 \r
1695         if (IS_ERR(pservice->cls)) {\r
1696                 ret = PTR_ERR(pservice->cls);\r
1697                 dev_err(dev, "class_create err:%d\n", ret);\r
1698                 goto err;\r
1699         }\r
1700 \r
1701         pservice->child_dev = device_create(pservice->cls, dev, pservice->dev_t, NULL, dev_name(dev));\r
1702 \r
1703         platform_set_drvdata(pdev, pservice);\r
1704 \r
1705         get_hw_info(pservice);\r
1706 \r
1707 \r
1708 #ifdef CONFIG_DEBUG_FS\r
1709         pservice->debugfs_dir = vcodec_debugfs_create_device_dir((char*)dev_name(dev), parent);\r
1710         if (pservice->debugfs_dir == NULL)\r
1711                 pr_err("create debugfs dir %s failed\n", dev_name(dev));\r
1712 \r
1713         pservice->debugfs_file_regs =\r
1714                 debugfs_create_file("regs", 0664,\r
1715                                     pservice->debugfs_dir, pservice,\r
1716                                     &debug_vcodec_fops);\r
1717 #endif\r
1718 \r
1719 #if defined(CONFIG_VCODEC_MMU)\r
1720         if (iommu_en) {\r
1721                 pservice->ion_client = rockchip_ion_client_create("vpu");\r
1722                 if (IS_ERR(pservice->ion_client)) {\r
1723                         dev_err(&pdev->dev, "failed to create ion client for vcodec");\r
1724                         return PTR_ERR(pservice->ion_client);\r
1725                 } else {\r
1726                         dev_info(&pdev->dev, "vcodec ion client create success!\n");\r
1727                 }\r
1728 \r
1729                 if (pservice->hw_info->hw_id == HEVC_ID)\r
1730                         sprintf(mmu_dev_dts_name, "iommu,hevc_mmu");\r
1731                 else\r
1732                         sprintf(mmu_dev_dts_name, "iommu,vpu_mmu");\r
1733 \r
1734                 pservice->mmu_dev = rockchip_get_sysmmu_device_by_compatible(mmu_dev_dts_name);\r
1735 \r
1736                 if (pservice->mmu_dev) {\r
1737                         platform_set_sysmmu(pservice->mmu_dev, pservice->dev);\r
1738                         iovmm_activate(pservice->dev);\r
1739                 }\r
1740         }\r
1741 #endif\r
1742 \r
1743         vpu_service_power_off(pservice);\r
1744         vcodec_exit_mode();\r
1745 \r
1746         pr_info("init success\n");\r
1747 \r
1748 #if HEVC_SIM_ENABLE\r
1749         if (pservice->hw_info->hw_id == HEVC_ID)\r
1750                 simulate_init(pservice);\r
1751 #endif\r
1752 \r
1753 #if HEVC_TEST_ENABLE\r
1754         hevc_test_case0(pservice);\r
1755 #endif\r
1756 \r
1757         return 0;\r
1758 \r
1759 err:\r
1760         pr_info("init failed\n");\r
1761         vpu_service_power_off(pservice);\r
1762         vpu_put_clk(pservice);\r
1763         wake_lock_destroy(&pservice->wake_lock);\r
1764 \r
1765         if (res)\r
1766                 devm_release_mem_region(&pdev->dev, res->start, resource_size(res));\r
1767         if (pservice->irq_enc > 0)\r
1768                 free_irq(pservice->irq_enc, (void *)pservice);\r
1769         if (pservice->irq_dec > 0)\r
1770                 free_irq(pservice->irq_dec, (void *)pservice);\r
1771 \r
1772         if (pservice->child_dev) {\r
1773                 device_destroy(pservice->cls, pservice->dev_t);\r
1774                 cdev_del(&pservice->cdev);\r
1775                 unregister_chrdev_region(pservice->dev_t, 1);\r
1776         }\r
1777 \r
1778         if (pservice->cls)\r
1779                 class_destroy(pservice->cls);\r
1780 \r
1781         return ret;\r
1782 }\r
1783 \r
1784 static int vcodec_remove(struct platform_device *pdev)\r
1785 {\r
1786         struct vpu_service_info *pservice = platform_get_drvdata(pdev);\r
1787         struct resource *res;\r
1788 \r
1789         device_destroy(pservice->cls, pservice->dev_t);\r
1790         class_destroy(pservice->cls);\r
1791         cdev_del(&pservice->cdev);\r
1792         unregister_chrdev_region(pservice->dev_t, 1);\r
1793 \r
1794         free_irq(pservice->irq_enc, (void *)&pservice->enc_dev);\r
1795         free_irq(pservice->irq_dec, (void *)&pservice->dec_dev);\r
1796         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
1797         devm_release_mem_region(&pdev->dev, res->start, resource_size(res));\r
1798         vpu_put_clk(pservice);\r
1799         wake_lock_destroy(&pservice->wake_lock);\r
1800 \r
1801 #ifdef CONFIG_DEBUG_FS\r
1802         debugfs_remove(pservice->debugfs_file_regs);\r
1803         debugfs_remove(pservice->debugfs_dir);\r
1804 #endif\r
1805 \r
1806         return 0;\r
1807 }\r
1808 \r
1809 #if defined(CONFIG_OF)\r
1810 static const struct of_device_id vcodec_service_dt_ids[] = {\r
1811         {.compatible = "vpu_service",},\r
1812         {.compatible = "rockchip,hevc_service",},\r
1813         {},\r
1814 };\r
1815 #endif\r
1816 \r
1817 static struct platform_driver vcodec_driver = {\r
1818         .probe = vcodec_probe,\r
1819         .remove = vcodec_remove,\r
1820         .driver = {\r
1821                 .name = "vcodec",\r
1822                 .owner = THIS_MODULE,\r
1823 #if defined(CONFIG_OF)\r
1824                 .of_match_table = of_match_ptr(vcodec_service_dt_ids),\r
1825 #endif\r
1826         },\r
1827 };\r
1828 \r
1829 static void get_hw_info(struct vpu_service_info *pservice)\r
1830 {\r
1831         VPUHwDecConfig_t *dec = &pservice->dec_config;\r
1832         VPUHwEncConfig_t *enc = &pservice->enc_config;\r
1833 \r
1834         if (pservice->dev_id == VCODEC_DEVICE_ID_VPU) {\r
1835                 u32 configReg   = pservice->dec_dev.hwregs[VPU_DEC_HWCFG0];\r
1836                 u32 asicID      = pservice->dec_dev.hwregs[0];\r
1837 \r
1838                 dec->h264Support    = (configReg >> DWL_H264_E) & 0x3U;\r
1839                 dec->jpegSupport    = (configReg >> DWL_JPEG_E) & 0x01U;\r
1840                 if (dec->jpegSupport && ((configReg >> DWL_PJPEG_E) & 0x01U))\r
1841                         dec->jpegSupport = JPEG_PROGRESSIVE;\r
1842                 dec->mpeg4Support   = (configReg >> DWL_MPEG4_E) & 0x3U;\r
1843                 dec->vc1Support     = (configReg >> DWL_VC1_E) & 0x3U;\r
1844                 dec->mpeg2Support   = (configReg >> DWL_MPEG2_E) & 0x01U;\r
1845                 dec->sorensonSparkSupport = (configReg >> DWL_SORENSONSPARK_E) & 0x01U;\r
1846                 dec->refBufSupport  = (configReg >> DWL_REF_BUFF_E) & 0x01U;\r
1847                 dec->vp6Support     = (configReg >> DWL_VP6_E) & 0x01U;\r
1848 \r
1849                 if (soc_is_rk3190() || soc_is_rk3288())\r
1850                         dec->maxDecPicWidth = 4096;\r
1851                 else if (cpu_is_rk3036() || cpu_is_rk312x())\r
1852                         dec->maxDecPicWidth = 1920;\r
1853                 else\r
1854                         dec->maxDecPicWidth = configReg & 0x07FFU;\r
1855 \r
1856                 /* 2nd Config register */\r
1857                 configReg   = pservice->dec_dev.hwregs[VPU_DEC_HWCFG1];\r
1858                 if (dec->refBufSupport) {\r
1859                         if ((configReg >> DWL_REF_BUFF_ILACE_E) & 0x01U)\r
1860                                 dec->refBufSupport |= 2;\r
1861                         if ((configReg >> DWL_REF_BUFF_DOUBLE_E) & 0x01U)\r
1862                                 dec->refBufSupport |= 4;\r
1863                 }\r
1864                 dec->customMpeg4Support = (configReg >> DWL_MPEG4_CUSTOM_E) & 0x01U;\r
1865                 dec->vp7Support     = (configReg >> DWL_VP7_E) & 0x01U;\r
1866                 dec->vp8Support     = (configReg >> DWL_VP8_E) & 0x01U;\r
1867                 dec->avsSupport     = (configReg >> DWL_AVS_E) & 0x01U;\r
1868 \r
1869                 /* JPEG xtensions */\r
1870                 if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U))\r
1871                         dec->jpegESupport = (configReg >> DWL_JPEG_EXT_E) & 0x01U;\r
1872                 else\r
1873                         dec->jpegESupport = JPEG_EXT_NOT_SUPPORTED;\r
1874 \r
1875                 if (((asicID >> 16) >= 0x9170U) || ((asicID >> 16) == 0x6731U) )\r
1876                         dec->rvSupport = (configReg >> DWL_RV_E) & 0x03U;\r
1877                 else\r
1878                         dec->rvSupport = RV_NOT_SUPPORTED;\r
1879                 dec->mvcSupport = (configReg >> DWL_MVC_E) & 0x03U;\r
1880 \r
1881                 if (dec->refBufSupport && (asicID >> 16) == 0x6731U )\r
1882                         dec->refBufSupport |= 8; /* enable HW support for offset */\r
1883 \r
1884                 /// invalidate fuse register value in rk319x vpu and following.\r
1885                 if (!soc_is_rk3190() && !soc_is_rk3288() && !cpu_is_rk3036() && !cpu_is_rk312x()) {\r
1886                         VPUHwFuseStatus_t hwFuseSts;\r
1887                         /* Decoder fuse configuration */\r
1888                         u32 fuseReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];\r
1889 \r
1890                         hwFuseSts.h264SupportFuse = (fuseReg >> DWL_H264_FUSE_E) & 0x01U;\r
1891                         hwFuseSts.mpeg4SupportFuse = (fuseReg >> DWL_MPEG4_FUSE_E) & 0x01U;\r
1892                         hwFuseSts.mpeg2SupportFuse = (fuseReg >> DWL_MPEG2_FUSE_E) & 0x01U;\r
1893                         hwFuseSts.sorensonSparkSupportFuse = (fuseReg >> DWL_SORENSONSPARK_FUSE_E) & 0x01U;\r
1894                         hwFuseSts.jpegSupportFuse = (fuseReg >> DWL_JPEG_FUSE_E) & 0x01U;\r
1895                         hwFuseSts.vp6SupportFuse = (fuseReg >> DWL_VP6_FUSE_E) & 0x01U;\r
1896                         hwFuseSts.vc1SupportFuse = (fuseReg >> DWL_VC1_FUSE_E) & 0x01U;\r
1897                         hwFuseSts.jpegProgSupportFuse = (fuseReg >> DWL_PJPEG_FUSE_E) & 0x01U;\r
1898                         hwFuseSts.rvSupportFuse = (fuseReg >> DWL_RV_FUSE_E) & 0x01U;\r
1899                         hwFuseSts.avsSupportFuse = (fuseReg >> DWL_AVS_FUSE_E) & 0x01U;\r
1900                         hwFuseSts.vp7SupportFuse = (fuseReg >> DWL_VP7_FUSE_E) & 0x01U;\r
1901                         hwFuseSts.vp8SupportFuse = (fuseReg >> DWL_VP8_FUSE_E) & 0x01U;\r
1902                         hwFuseSts.customMpeg4SupportFuse = (fuseReg >> DWL_CUSTOM_MPEG4_FUSE_E) & 0x01U;\r
1903                         hwFuseSts.mvcSupportFuse = (fuseReg >> DWL_MVC_FUSE_E) & 0x01U;\r
1904 \r
1905                         /* check max. decoder output width */\r
1906 \r
1907                         if (fuseReg & 0x8000U)\r
1908                                 hwFuseSts.maxDecPicWidthFuse = 1920;\r
1909                         else if (fuseReg & 0x4000U)\r
1910                                 hwFuseSts.maxDecPicWidthFuse = 1280;\r
1911                         else if (fuseReg & 0x2000U)\r
1912                                 hwFuseSts.maxDecPicWidthFuse = 720;\r
1913                         else if (fuseReg & 0x1000U)\r
1914                                 hwFuseSts.maxDecPicWidthFuse = 352;\r
1915                         else    /* remove warning */\r
1916                                 hwFuseSts.maxDecPicWidthFuse = 352;\r
1917 \r
1918                         hwFuseSts.refBufSupportFuse = (fuseReg >> DWL_REF_BUFF_FUSE_E) & 0x01U;\r
1919 \r
1920                         /* Pp configuration */\r
1921                         configReg = pservice->dec_dev.hwregs[VPU_PP_HW_SYNTH_CFG];\r
1922 \r
1923                         if ((configReg >> DWL_PP_E) & 0x01U) {\r
1924                                 dec->ppSupport = 1;\r
1925                                 dec->maxPpOutPicWidth = configReg & 0x07FFU;\r
1926                                 /*pHwCfg->ppConfig = (configReg >> DWL_CFG_E) & 0x0FU; */\r
1927                                 dec->ppConfig = configReg;\r
1928                         } else {\r
1929                                 dec->ppSupport = 0;\r
1930                                 dec->maxPpOutPicWidth = 0;\r
1931                                 dec->ppConfig = 0;\r
1932                         }\r
1933 \r
1934                         /* check the HW versio */\r
1935                         if (((asicID >> 16) >= 0x8190U) || ((asicID >> 16) == 0x6731U)) {\r
1936                                 /* Pp configuration */\r
1937                                 configReg = pservice->dec_dev.hwregs[VPU_DEC_HW_FUSE_CFG];\r
1938                                 if ((configReg >> DWL_PP_E) & 0x01U) {\r
1939                                         /* Pp fuse configuration */\r
1940                                         u32 fuseRegPp = pservice->dec_dev.hwregs[VPU_PP_HW_FUSE_CFG];\r
1941 \r
1942                                         if ((fuseRegPp >> DWL_PP_FUSE_E) & 0x01U) {\r
1943                                                 hwFuseSts.ppSupportFuse = 1;\r
1944                                                 /* check max. pp output width */\r
1945                                                 if (fuseRegPp & 0x8000U)\r
1946                                                         hwFuseSts.maxPpOutPicWidthFuse = 1920;\r
1947                                                 else if (fuseRegPp & 0x4000U)\r
1948                                                         hwFuseSts.maxPpOutPicWidthFuse = 1280;\r
1949                                                 else if (fuseRegPp & 0x2000U)\r
1950                                                         hwFuseSts.maxPpOutPicWidthFuse = 720;\r
1951                                                 else if (fuseRegPp & 0x1000U)\r
1952                                                         hwFuseSts.maxPpOutPicWidthFuse = 352;\r
1953                                                 else\r
1954                                                         hwFuseSts.maxPpOutPicWidthFuse = 352;\r
1955                                                 hwFuseSts.ppConfigFuse = fuseRegPp;\r
1956                                         } else {\r
1957                                                 hwFuseSts.ppSupportFuse = 0;\r
1958                                                 hwFuseSts.maxPpOutPicWidthFuse = 0;\r
1959                                                 hwFuseSts.ppConfigFuse = 0;\r
1960                                         }\r
1961                                 } else {\r
1962                                         hwFuseSts.ppSupportFuse = 0;\r
1963                                         hwFuseSts.maxPpOutPicWidthFuse = 0;\r
1964                                         hwFuseSts.ppConfigFuse = 0;\r
1965                                 }\r
1966 \r
1967                                 if (dec->maxDecPicWidth > hwFuseSts.maxDecPicWidthFuse)\r
1968                                         dec->maxDecPicWidth = hwFuseSts.maxDecPicWidthFuse;\r
1969                                 if (dec->maxPpOutPicWidth > hwFuseSts.maxPpOutPicWidthFuse)\r
1970                                         dec->maxPpOutPicWidth = hwFuseSts.maxPpOutPicWidthFuse;\r
1971                                 if (!hwFuseSts.h264SupportFuse) dec->h264Support = H264_NOT_SUPPORTED;\r
1972                                 if (!hwFuseSts.mpeg4SupportFuse) dec->mpeg4Support = MPEG4_NOT_SUPPORTED;\r
1973                                 if (!hwFuseSts.customMpeg4SupportFuse) dec->customMpeg4Support = MPEG4_CUSTOM_NOT_SUPPORTED;\r
1974                                 if (!hwFuseSts.jpegSupportFuse) dec->jpegSupport = JPEG_NOT_SUPPORTED;\r
1975                                 if ((dec->jpegSupport == JPEG_PROGRESSIVE) && !hwFuseSts.jpegProgSupportFuse)\r
1976                                         dec->jpegSupport = JPEG_BASELINE;\r
1977                                 if (!hwFuseSts.mpeg2SupportFuse) dec->mpeg2Support = MPEG2_NOT_SUPPORTED;\r
1978                                 if (!hwFuseSts.vc1SupportFuse) dec->vc1Support = VC1_NOT_SUPPORTED;\r
1979                                 if (!hwFuseSts.vp6SupportFuse) dec->vp6Support = VP6_NOT_SUPPORTED;\r
1980                                 if (!hwFuseSts.vp7SupportFuse) dec->vp7Support = VP7_NOT_SUPPORTED;\r
1981                                 if (!hwFuseSts.vp8SupportFuse) dec->vp8Support = VP8_NOT_SUPPORTED;\r
1982                                 if (!hwFuseSts.ppSupportFuse) dec->ppSupport = PP_NOT_SUPPORTED;\r
1983 \r
1984                                 /* check the pp config vs fuse status */\r
1985                                 if ((dec->ppConfig & 0xFC000000) && ((hwFuseSts.ppConfigFuse & 0xF0000000) >> 5)) {\r
1986                                         u32 deInterlace = ((dec->ppConfig & PP_DEINTERLACING) >> 25);\r
1987                                         u32 alphaBlend  = ((dec->ppConfig & PP_ALPHA_BLENDING) >> 24);\r
1988                                         u32 deInterlaceFuse = (((hwFuseSts.ppConfigFuse >> 5) & PP_DEINTERLACING) >> 25);\r
1989                                         u32 alphaBlendFuse  = (((hwFuseSts.ppConfigFuse >> 5) & PP_ALPHA_BLENDING) >> 24);\r
1990 \r
1991                                         if (deInterlace && !deInterlaceFuse) dec->ppConfig &= 0xFD000000;\r
1992                                         if (alphaBlend && !alphaBlendFuse) dec->ppConfig &= 0xFE000000;\r
1993                                 }\r
1994                                 if (!hwFuseSts.sorensonSparkSupportFuse) dec->sorensonSparkSupport = SORENSON_SPARK_NOT_SUPPORTED;\r
1995                                 if (!hwFuseSts.refBufSupportFuse)   dec->refBufSupport = REF_BUF_NOT_SUPPORTED;\r
1996                                 if (!hwFuseSts.rvSupportFuse)       dec->rvSupport = RV_NOT_SUPPORTED;\r
1997                                 if (!hwFuseSts.avsSupportFuse)      dec->avsSupport = AVS_NOT_SUPPORTED;\r
1998                                 if (!hwFuseSts.mvcSupportFuse)      dec->mvcSupport = MVC_NOT_SUPPORTED;\r
1999                         }\r
2000                 }\r
2001 \r
2002                 if (!cpu_is_rk3036()) {\r
2003                         configReg = pservice->enc_dev.hwregs[63];\r
2004                         enc->maxEncodedWidth = configReg & ((1 << 11) - 1);\r
2005                         enc->h264Enabled = (configReg >> 27) & 1;\r
2006                         enc->mpeg4Enabled = (configReg >> 26) & 1;\r
2007                         enc->jpegEnabled = (configReg >> 25) & 1;\r
2008                         enc->vsEnabled = (configReg >> 24) & 1;\r
2009                         enc->rgbEnabled = (configReg >> 28) & 1;\r
2010                         /*enc->busType = (configReg >> 20) & 15;\r
2011                         enc->synthesisLanguage = (configReg >> 16) & 15;\r
2012                         enc->busWidth = (configReg >> 12) & 15;*/\r
2013                         enc->reg_size = pservice->reg_size;\r
2014                         enc->reserv[0] = enc->reserv[1] = 0;\r
2015                 }\r
2016 \r
2017                 pservice->auto_freq = soc_is_rk2928g() || soc_is_rk2928l() || soc_is_rk2926() || soc_is_rk3288();\r
2018                 if (pservice->auto_freq) {\r
2019                         pr_info("vpu_service set to auto frequency mode\n");\r
2020                         atomic_set(&pservice->freq_status, VPU_FREQ_BUT);\r
2021                 }\r
2022 \r
2023                 pservice->bug_dec_addr = cpu_is_rk30xx();\r
2024         } else {\r
2025                 if (cpu_is_rk3036()  || cpu_is_rk312x())\r
2026                         dec->maxDecPicWidth = 1920;\r
2027                 else\r
2028                         dec->maxDecPicWidth = 4096;\r
2029                 /* disable frequency switch in hevc.*/\r
2030                 pservice->auto_freq = false;\r
2031         }\r
2032 }\r
2033 \r
2034 static irqreturn_t vdpu_irq(int irq, void *dev_id)\r
2035 {\r
2036         struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
2037         vpu_device *dev = &pservice->dec_dev;\r
2038         u32 raw_status;\r
2039         u32 irq_status;\r
2040 \r
2041         vcodec_enter_mode_nolock(pservice->dev_id, &pservice->reserved_mode);\r
2042 \r
2043         irq_status = raw_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);\r
2044 \r
2045         pr_debug("dec_irq\n");\r
2046 \r
2047         if (irq_status & DEC_INTERRUPT_BIT) {\r
2048                 pr_debug("dec_isr dec %x\n", irq_status);\r
2049                 if ((irq_status & 0x40001) == 0x40001)\r
2050                 {\r
2051                         do {\r
2052                                 irq_status = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);\r
2053                         } while ((irq_status & 0x40001) == 0x40001);\r
2054                 }\r
2055 \r
2056                 /* clear dec IRQ */\r
2057                 if (pservice->hw_info->hw_id != HEVC_ID)\r
2058                         writel(irq_status & (~DEC_INTERRUPT_BIT|DEC_BUFFER_EMPTY_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER);\r
2059                 else\r
2060                         writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER);\r
2061                 atomic_add(1, &dev->irq_count_codec);\r
2062         }\r
2063 \r
2064         if (pservice->hw_info->hw_id != HEVC_ID) {\r
2065                 irq_status = readl(dev->hwregs + PP_INTERRUPT_REGISTER);\r
2066                 if (irq_status & PP_INTERRUPT_BIT) {\r
2067                         pr_debug("vdpu_isr pp  %x\n", irq_status);\r
2068                         /* clear pp IRQ */\r
2069                         writel(irq_status & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);\r
2070                         atomic_add(1, &dev->irq_count_pp);\r
2071                 }\r
2072         }\r
2073 \r
2074         pservice->irq_status = raw_status;\r
2075 \r
2076         vcodec_exit_mode_nolock(pservice->dev_id, pservice->reserved_mode);\r
2077 \r
2078         return IRQ_WAKE_THREAD;\r
2079 }\r
2080 \r
2081 static irqreturn_t vdpu_isr(int irq, void *dev_id)\r
2082 {\r
2083         struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
2084         vpu_device *dev = &pservice->dec_dev;\r
2085 \r
2086         mutex_lock(&pservice->lock);\r
2087         if (atomic_read(&dev->irq_count_codec)) {\r
2088 #if VPU_SERVICE_SHOW_TIME\r
2089                 do_gettimeofday(&dec_end);\r
2090                 pr_info("dec task: %ld ms\n",\r
2091                         (dec_end.tv_sec  - dec_start.tv_sec)  * 1000 +\r
2092                         (dec_end.tv_usec - dec_start.tv_usec) / 1000);\r
2093 #endif\r
2094                 atomic_sub(1, &dev->irq_count_codec);\r
2095                 if (NULL == pservice->reg_codec) {\r
2096                         pr_err("error: dec isr with no task waiting\n");\r
2097                 } else {\r
2098                         reg_from_run_to_done(pservice, pservice->reg_codec);\r
2099                 }\r
2100         }\r
2101 \r
2102         if (atomic_read(&dev->irq_count_pp)) {\r
2103 \r
2104 #if VPU_SERVICE_SHOW_TIME\r
2105                 do_gettimeofday(&pp_end);\r
2106                 printk("pp  task: %ld ms\n",\r
2107                         (pp_end.tv_sec  - pp_start.tv_sec)  * 1000 +\r
2108                         (pp_end.tv_usec - pp_start.tv_usec) / 1000);\r
2109 #endif\r
2110 \r
2111                 atomic_sub(1, &dev->irq_count_pp);\r
2112                 if (NULL == pservice->reg_pproc) {\r
2113                         pr_err("error: pp isr with no task waiting\n");\r
2114                 } else {\r
2115                         reg_from_run_to_done(pservice, pservice->reg_pproc);\r
2116                 }\r
2117         }\r
2118         try_set_reg(pservice);\r
2119         mutex_unlock(&pservice->lock);\r
2120         return IRQ_HANDLED;\r
2121 }\r
2122 \r
2123 static irqreturn_t vepu_irq(int irq, void *dev_id)\r
2124 {\r
2125         struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
2126         vpu_device *dev = &pservice->enc_dev;\r
2127         u32 irq_status;\r
2128 \r
2129         vcodec_enter_mode_nolock(pservice->dev_id,  &pservice->reserved_mode);\r
2130         irq_status= readl(dev->hwregs + ENC_INTERRUPT_REGISTER);\r
2131 \r
2132         pr_debug("vepu_irq irq status %x\n", irq_status);\r
2133 \r
2134 #if VPU_SERVICE_SHOW_TIME\r
2135         do_gettimeofday(&enc_end);\r
2136         pr_info("enc task: %ld ms\n",\r
2137                 (enc_end.tv_sec  - enc_start.tv_sec)  * 1000 +\r
2138                 (enc_end.tv_usec - enc_start.tv_usec) / 1000);\r
2139 #endif\r
2140         if (likely(irq_status & ENC_INTERRUPT_BIT)) {\r
2141                 /* clear enc IRQ */\r
2142                 writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);\r
2143                 atomic_add(1, &dev->irq_count_codec);\r
2144         }\r
2145 \r
2146         pservice->irq_status = irq_status;\r
2147 \r
2148         vcodec_exit_mode_nolock(pservice->dev_id, pservice->reserved_mode);\r
2149 \r
2150         return IRQ_WAKE_THREAD;\r
2151 }\r
2152 \r
2153 static irqreturn_t vepu_isr(int irq, void *dev_id)\r
2154 {\r
2155         struct vpu_service_info *pservice = (struct vpu_service_info*)dev_id;\r
2156         vpu_device *dev = &pservice->enc_dev;\r
2157 \r
2158         mutex_lock(&pservice->lock);\r
2159         if (atomic_read(&dev->irq_count_codec)) {\r
2160                 atomic_sub(1, &dev->irq_count_codec);\r
2161                 if (NULL == pservice->reg_codec) {\r
2162                         pr_err("error: enc isr with no task waiting\n");\r
2163                 } else {\r
2164                         reg_from_run_to_done(pservice, pservice->reg_codec);\r
2165                 }\r
2166         }\r
2167         try_set_reg(pservice);\r
2168         mutex_unlock(&pservice->lock);\r
2169         return IRQ_HANDLED;\r
2170 }\r
2171 \r
2172 static int __init vcodec_service_init(void)\r
2173 {\r
2174         int ret;\r
2175 \r
2176         if ((ret = platform_driver_register(&vcodec_driver)) != 0) {\r
2177                 pr_err("Platform device register failed (%d).\n", ret);\r
2178                 return ret;\r
2179         }\r
2180 \r
2181 #ifdef CONFIG_DEBUG_FS\r
2182         vcodec_debugfs_init();\r
2183 #endif\r
2184 \r
2185         return ret;\r
2186 }\r
2187 \r
2188 static void __exit vcodec_service_exit(void)\r
2189 {\r
2190 #ifdef CONFIG_DEBUG_FS\r
2191         vcodec_debugfs_exit();\r
2192 #endif\r
2193 \r
2194         platform_driver_unregister(&vcodec_driver);\r
2195 }\r
2196 \r
2197 module_init(vcodec_service_init);\r
2198 module_exit(vcodec_service_exit);\r
2199 \r
2200 #ifdef CONFIG_DEBUG_FS\r
2201 #include <linux/seq_file.h>\r
2202 \r
2203 static int vcodec_debugfs_init()\r
2204 {\r
2205         parent = debugfs_create_dir("vcodec", NULL);\r
2206         if (!parent)\r
2207                 return -1;\r
2208 \r
2209         return 0;\r
2210 }\r
2211 \r
2212 static void vcodec_debugfs_exit()\r
2213 {\r
2214         debugfs_remove(parent);\r
2215 }\r
2216 \r
2217 static struct dentry* vcodec_debugfs_create_device_dir(char *dirname, struct dentry *parent)\r
2218 {\r
2219         return debugfs_create_dir(dirname, parent);\r
2220 }\r
2221 \r
2222 static int debug_vcodec_show(struct seq_file *s, void *unused)\r
2223 {\r
2224         struct vpu_service_info *pservice = s->private;\r
2225         unsigned int i, n;\r
2226         vpu_reg *reg, *reg_tmp;\r
2227         vpu_session *session, *session_tmp;\r
2228 \r
2229         mutex_lock(&pservice->lock);\r
2230         vpu_service_power_on(pservice);\r
2231         if (pservice->hw_info->hw_id != HEVC_ID) {\r
2232                 seq_printf(s, "\nENC Registers:\n");\r
2233                 n = pservice->enc_dev.iosize >> 2;\r
2234                 for (i = 0; i < n; i++) {\r
2235                         seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->enc_dev.hwregs + i));\r
2236                 }\r
2237         }\r
2238         seq_printf(s, "\nDEC Registers:\n");\r
2239         n = pservice->dec_dev.iosize >> 2;\r
2240         for (i = 0; i < n; i++)\r
2241                 seq_printf(s, "\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i));\r
2242 \r
2243         seq_printf(s, "\nvpu service status:\n");\r
2244         list_for_each_entry_safe(session, session_tmp, &pservice->session, list_session) {\r
2245                 seq_printf(s, "session pid %d type %d:\n", session->pid, session->type);\r
2246                 /*seq_printf(s, "waiting reg set %d\n");*/\r
2247                 list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) {\r
2248                         seq_printf(s, "waiting register set\n");\r
2249                 }\r
2250                 list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) {\r
2251                         seq_printf(s, "running register set\n");\r
2252                 }\r
2253                 list_for_each_entry_safe(reg, reg_tmp, &session->done, session_link) {\r
2254                         seq_printf(s, "done    register set\n");\r
2255                 }\r
2256         }\r
2257         mutex_unlock(&pservice->lock);\r
2258 \r
2259         return 0;\r
2260 }\r
2261 \r
2262 static int debug_vcodec_open(struct inode *inode, struct file *file)\r
2263 {\r
2264         return single_open(file, debug_vcodec_show, inode->i_private);\r
2265 }\r
2266 \r
2267 #endif\r
2268 \r
2269 #if HEVC_TEST_ENABLE & defined(CONFIG_ION_ROCKCHIP)\r
2270 #include "hevc_test_inc/pps_00.h"\r
2271 #include "hevc_test_inc/register_00.h"\r
2272 #include "hevc_test_inc/rps_00.h"\r
2273 #include "hevc_test_inc/scaling_list_00.h"\r
2274 #include "hevc_test_inc/stream_00.h"\r
2275 \r
2276 #include "hevc_test_inc/pps_01.h"\r
2277 #include "hevc_test_inc/register_01.h"\r
2278 #include "hevc_test_inc/rps_01.h"\r
2279 #include "hevc_test_inc/scaling_list_01.h"\r
2280 #include "hevc_test_inc/stream_01.h"\r
2281 \r
2282 #include "hevc_test_inc/cabac.h"\r
2283 \r
2284 extern struct ion_client *rockchip_ion_client_create(const char * name);\r
2285 \r
2286 static struct ion_client *ion_client = NULL;\r
2287 u8* get_align_ptr(u8* tbl, int len, u32 *phy)\r
2288 {\r
2289         int size = (len+15) & (~15);\r
2290         struct ion_handle *handle;\r
2291         u8 *ptr;// = (u8*)kzalloc(size, GFP_KERNEL);\r
2292 \r
2293         if (ion_client == NULL)\r
2294                 ion_client = rockchip_ion_client_create("vcodec");\r
2295 \r
2296         handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0);\r
2297 \r
2298         ptr = ion_map_kernel(ion_client, handle);\r
2299 \r
2300         ion_phys(ion_client, handle, phy, &size);\r
2301 \r
2302         memcpy(ptr, tbl, len);\r
2303 \r
2304         return ptr;\r
2305 }\r
2306 \r
2307 u8* get_align_ptr_no_copy(int len, u32 *phy)\r
2308 {\r
2309         int size = (len+15) & (~15);\r
2310         struct ion_handle *handle;\r
2311         u8 *ptr;\r
2312 \r
2313         if (ion_client == NULL)\r
2314                 ion_client = rockchip_ion_client_create("vcodec");\r
2315 \r
2316         handle = ion_alloc(ion_client, (size_t)len, 16, ION_HEAP(ION_CMA_HEAP_ID), 0);\r
2317 \r
2318         ptr = ion_map_kernel(ion_client, handle);\r
2319 \r
2320         ion_phys(ion_client, handle, phy, &size);\r
2321 \r
2322         return ptr;\r
2323 }\r
2324 \r
2325 #define TEST_CNT    2\r
2326 static int hevc_test_case0(vpu_service_info *pservice)\r
2327 {\r
2328         vpu_session session;\r
2329         vpu_reg *reg;\r
2330         unsigned long size = 272;//sizeof(register_00); // registers array length\r
2331         int testidx = 0;\r
2332         int ret = 0;\r
2333 \r
2334         u8 *pps_tbl[TEST_CNT];\r
2335         u8 *register_tbl[TEST_CNT];\r
2336         u8 *rps_tbl[TEST_CNT];\r
2337         u8 *scaling_list_tbl[TEST_CNT];\r
2338         u8 *stream_tbl[TEST_CNT];\r
2339 \r
2340         int stream_size[2];\r
2341         int pps_size[2];\r
2342         int rps_size[2];\r
2343         int scl_size[2];\r
2344         int cabac_size[2];\r
2345 \r
2346         u32 phy_pps;\r
2347         u32 phy_rps;\r
2348         u32 phy_scl;\r
2349         u32 phy_str;\r
2350         u32 phy_yuv;\r
2351         u32 phy_ref;\r
2352         u32 phy_cabac;\r
2353 \r
2354         volatile u8 *stream_buf;\r
2355         volatile u8 *pps_buf;\r
2356         volatile u8 *rps_buf;\r
2357         volatile u8 *scl_buf;\r
2358         volatile u8 *yuv_buf;\r
2359         volatile u8 *cabac_buf;\r
2360         volatile u8 *ref_buf;\r
2361 \r
2362         u8 *pps;\r
2363         u8 *yuv[2];\r
2364         int i;\r
2365 \r
2366         pps_tbl[0] = pps_00;\r
2367         pps_tbl[1] = pps_01;\r
2368 \r
2369         register_tbl[0] = register_00;\r
2370         register_tbl[1] = register_01;\r
2371 \r
2372         rps_tbl[0] = rps_00;\r
2373         rps_tbl[1] = rps_01;\r
2374 \r
2375         scaling_list_tbl[0] = scaling_list_00;\r
2376         scaling_list_tbl[1] = scaling_list_01;\r
2377 \r
2378         stream_tbl[0] = stream_00;\r
2379         stream_tbl[1] = stream_01;\r
2380 \r
2381         stream_size[0] = sizeof(stream_00);\r
2382         stream_size[1] = sizeof(stream_01);\r
2383 \r
2384         pps_size[0] = sizeof(pps_00);\r
2385         pps_size[1] = sizeof(pps_01);\r
2386 \r
2387         rps_size[0] = sizeof(rps_00);\r
2388         rps_size[1] = sizeof(rps_01);\r
2389 \r
2390         scl_size[0] = sizeof(scaling_list_00);\r
2391         scl_size[1] = sizeof(scaling_list_01);\r
2392 \r
2393         cabac_size[0] = sizeof(Cabac_table);\r
2394         cabac_size[1] = sizeof(Cabac_table);\r
2395 \r
2396         /* create session */\r
2397         session.pid = current->pid;\r
2398         session.type = VPU_DEC;\r
2399         INIT_LIST_HEAD(&session.waiting);\r
2400         INIT_LIST_HEAD(&session.running);\r
2401         INIT_LIST_HEAD(&session.done);\r
2402         INIT_LIST_HEAD(&session.list_session);\r
2403         init_waitqueue_head(&session.wait);\r
2404         atomic_set(&session.task_running, 0);\r
2405         list_add_tail(&session.list_session, &pservice->session);\r
2406 \r
2407         yuv[0] = get_align_ptr_no_copy(256*256*2, &phy_yuv);\r
2408         yuv[1] = get_align_ptr_no_copy(256*256*2, &phy_ref);\r
2409 \r
2410         while (testidx < TEST_CNT) {\r
2411                 /* create registers */\r
2412                 reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);\r
2413                 if (NULL == reg) {\r
2414                         pr_err("error: kmalloc fail in reg_init\n");\r
2415                         return -1;\r
2416                 }\r
2417 \r
2418                 if (size > pservice->reg_size) {\r
2419                         printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
2420                         size = pservice->reg_size;\r
2421                 }\r
2422                 reg->session = &session;\r
2423                 reg->type = session.type;\r
2424                 reg->size = size;\r
2425                 reg->freq = VPU_FREQ_DEFAULT;\r
2426                 reg->reg = (unsigned long *)&reg[1];\r
2427                 INIT_LIST_HEAD(&reg->session_link);\r
2428                 INIT_LIST_HEAD(&reg->status_link);\r
2429 \r
2430                 /* TODO: stuff registers */\r
2431                 memcpy(&reg->reg[0], register_tbl[testidx], /*sizeof(register_00)*/ 176);\r
2432 \r
2433                 stream_buf = get_align_ptr(stream_tbl[testidx], stream_size[testidx], &phy_str);\r
2434                 pps_buf = get_align_ptr(pps_tbl[0], pps_size[0], &phy_pps);\r
2435                 rps_buf = get_align_ptr(rps_tbl[testidx], rps_size[testidx], &phy_rps);\r
2436                 scl_buf = get_align_ptr(scaling_list_tbl[testidx], scl_size[testidx], &phy_scl);\r
2437                 cabac_buf = get_align_ptr(Cabac_table, cabac_size[testidx], &phy_cabac);\r
2438 \r
2439                 pps = pps_buf;\r
2440 \r
2441                 /* TODO: replace reigster address */\r
2442                 for (i=0; i<64; i++) {\r
2443                         u32 scaling_offset;\r
2444                         u32 tmp;\r
2445 \r
2446                         scaling_offset = (u32)pps[i*80+74];\r
2447                         scaling_offset += (u32)pps[i*80+75] << 8;\r
2448                         scaling_offset += (u32)pps[i*80+76] << 16;\r
2449                         scaling_offset += (u32)pps[i*80+77] << 24;\r
2450 \r
2451                         tmp = phy_scl + scaling_offset;\r
2452 \r
2453                         pps[i*80+74] = tmp & 0xff;\r
2454                         pps[i*80+75] = (tmp >> 8) & 0xff;\r
2455                         pps[i*80+76] = (tmp >> 16) & 0xff;\r
2456                         pps[i*80+77] = (tmp >> 24) & 0xff;\r
2457                 }\r
2458 \r
2459                 printk("%s %d, phy stream %08x, phy pps %08x, phy rps %08x\n",\r
2460                         __func__, __LINE__, phy_str, phy_pps, phy_rps);\r
2461 \r
2462                 reg->reg[1] = 0x21;\r
2463                 reg->reg[4] = phy_str;\r
2464                 reg->reg[5] = ((stream_size[testidx]+15)&(~15))+64;\r
2465                 reg->reg[6] = phy_cabac;\r
2466                 reg->reg[7] = testidx?phy_ref:phy_yuv;\r
2467                 reg->reg[42] = phy_pps;\r
2468                 reg->reg[43] = phy_rps;\r
2469                 for (i = 10; i <= 24; i++)\r
2470                         reg->reg[i] = phy_yuv;\r
2471 \r
2472                 mutex_lock(&pservice->lock);\r
2473                 list_add_tail(&reg->status_link, &pservice->waiting);\r
2474                 list_add_tail(&reg->session_link, &session.waiting);\r
2475                 mutex_unlock(&pservice->lock);\r
2476 \r
2477                 printk("%s %d %p\n", __func__, __LINE__, pservice);\r
2478 \r
2479                 /* stuff hardware */\r
2480                 try_set_reg(pservice);\r
2481 \r
2482                 /* wait for result */\r
2483                 ret = wait_event_timeout(session.wait, !list_empty(&session.done), VPU_TIMEOUT_DELAY);\r
2484                 if (!list_empty(&session.done)) {\r
2485                         if (ret < 0)\r
2486                                 pr_err("warning: pid %d wait task sucess but wait_evernt ret %d\n", session.pid, ret);\r
2487                         ret = 0;\r
2488                 } else {\r
2489                         if (unlikely(ret < 0)) {\r
2490                                 pr_err("error: pid %d wait task ret %d\n", session.pid, ret);\r
2491                         } else if (0 == ret) {\r
2492                                 pr_err("error: pid %d wait %d task done timeout\n", session.pid, atomic_read(&session.task_running));\r
2493                                 ret = -ETIMEDOUT;\r
2494                         }\r
2495                 }\r
2496                 if (ret < 0) {\r
2497                         int task_running = atomic_read(&session.task_running);\r
2498                         int n;\r
2499                         mutex_lock(&pservice->lock);\r
2500                         vpu_service_dump(pservice);\r
2501                         if (task_running) {\r
2502                                 atomic_set(&session.task_running, 0);\r
2503                                 atomic_sub(task_running, &pservice->total_running);\r
2504                                 printk("%d task is running but not return, reset hardware...", task_running);\r
2505                                 vpu_reset(pservice);\r
2506                                 printk("done\n");\r
2507                         }\r
2508                         vpu_service_session_clear(pservice, &session);\r
2509                         mutex_unlock(&pservice->lock);\r
2510 \r
2511                         printk("\nDEC Registers:\n");\r
2512                         n = pservice->dec_dev.iosize >> 2;\r
2513                         for (i=0; i<n; i++)\r
2514                                 printk("\tswreg%d = %08X\n", i, readl(pservice->dec_dev.hwregs + i));\r
2515 \r
2516                         pr_err("test index %d failed\n", testidx);\r
2517                         break;\r
2518                 } else {\r
2519                         pr_info("test index %d success\n", testidx);\r
2520 \r
2521                         vpu_reg *reg = list_entry(session.done.next, vpu_reg, session_link);\r
2522 \r
2523                         for (i=0; i<68; i++) {\r
2524                                 if (i % 4 == 0)\r
2525                                         printk("%02d: ", i);\r
2526                                 printk("%08x ", reg->reg[i]);\r
2527                                 if ((i+1) % 4 == 0)\r
2528                                         printk("\n");\r
2529                         }\r
2530 \r
2531                         testidx++;\r
2532                 }\r
2533 \r
2534                 reg_deinit(pservice, reg);\r
2535         }\r
2536 \r
2537         return 0;\r
2538 }\r
2539 \r
2540 #endif\r
2541 \r