tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / misc / sprd_coda7l / vpu.c
1 /*\r
2  * vpu.c\r
3  *\r
4  * linux device driver for VPU.\r
5  *\r
6  * Copyright (C) 2006 - 2013  CHIPS&MEDIA INC.\r
7  *\r
8  * This library is free software; you can redistribute it and/or modify it under\r
9  * the terms of the GNU Lesser General Public License as published by the Free\r
10  * Software Foundation; either version 2.1 of the License, or (at your option)\r
11  * any later version.\r
12  *\r
13  * This library is distributed in the hope that it will be useful, but WITHOUT\r
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
15  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more\r
16  * details.\r
17  *\r
18  * You should have received a copy of the GNU Lesser General Public License\r
19  * along with this library; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin St, Fifth Floor, Boston, MA\r
21  * 02110-1301  USA\r
22  *\r
23  */\r
24 \r
25 #include <linux/kernel.h>\r
26 #include <linux/mm.h>\r
27 #include <linux/interrupt.h>\r
28 #include <linux/ioport.h>\r
29 #include <linux/module.h>\r
30 #include <linux/platform_device.h>\r
31 #include <linux/dma-mapping.h>\r
32 #include <linux/wait.h>\r
33 #include <linux/list.h>\r
34 #include <linux/clk.h>\r
35 #include <linux/delay.h>\r
36 #include <linux/uaccess.h>\r
37 #include <linux/cdev.h>\r
38 #include <linux/slab.h>\r
39 #include <linux/sched.h>\r
40 #include <linux/miscdevice.h>\r
41 #include <linux/of_device.h>\r
42 #include <linux/of_address.h>\r
43 #include <linux/of_irq.h>\r
44 //#include <mach/hardware.h>\r
45 //#include <mach/sci_glb_regs.h>\r
46 #include <linux/sprd_iommu.h>\r
47 \r
48 #include <soc/sprd/sci.h>\r
49 #include <soc/sprd/sci_glb_regs.h>\r
50 \r
51 #include "vpuconfig.h"\r
52 #include "vpu.h"\r
53 #include "TShark2_CODEC_AHB_Control_Register.h"\r
54 \r
55 #define LOG_TAG "CNM_VPU_DRV"\r
56 \r
57 \r
58 /* definitions to be changed as customer  configuration */\r
59 /* if you want to have clock gating scheme frame by frame */\r
60 /* #define VPU_SUPPORT_CLOCK_CONTROL */\r
61 \r
62 /* if the driver want to use interrupt service from kernel ISR */\r
63 #define VPU_SUPPORT_ISR\r
64 #ifdef VPU_SUPPORT_ISR\r
65 /* if the driver want to disable and enable IRQ whenever interrupt asserted. */\r
66 //#define VPU_IRQ_CONTROL\r
67 #endif\r
68 \r
69 /* if the platform driver knows the name of this driver */\r
70 /* VPU_PLATFORM_DEVICE_NAME */\r
71 \r
72 #define VPU_SUPPORT_PLATFORM_DRIVER_REGISTER\r
73 \r
74 /* if this driver knows the dedicated video memory address */\r
75 //#define VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
76 \r
77 #define VPU_PLATFORM_DEVICE_NAME "vdec"\r
78 #define VPU_CLK_NAME "vcodec"\r
79 #define VPU_DEV_NAME "vpu"\r
80 \r
81 /* if the platform driver knows this driver */\r
82 /* the definition of VPU_REG_BASE_ADDR and VPU_REG_SIZE are not meaningful */\r
83 \r
84 //Set register 0x3000_0110(phy_addr)\r
85 #define VPU_AXI_CLK_ADDR (0x62000004)\r
86 #define VPU_AXI_CLK_ENABLE 0x0A04060A\r
87 #define VPU_AXI_CLK_DISABLE 0x0A04040A\r
88 \r
89 #define VPU_REG_BASE_ADDR 0x62100000\r
90 #define VPU_REG_SIZE (0x4000*MAX_NUM_VPU_CORE)\r
91 \r
92 #ifdef VPU_SUPPORT_ISR\r
93 #define VPU_IRQ_NUM (23+32)\r
94 #endif\r
95 \r
96 /* this definition is only for chipsnmedia FPGA board env */\r
97 /* so for SOC env of customers can be ignored */\r
98 \r
99 \r
100 #ifndef VM_RESERVED     /*for kernel up to 3.7.0 version*/\r
101 # define  VM_RESERVED   (VM_DONTEXPAND | VM_DONTDUMP)\r
102 #endif\r
103 \r
104 #define VPU_MINOR MISC_DYNAMIC_MINOR\r
105 \r
106 \r
107 typedef struct vpu_drv_context_t {\r
108     struct fasync_struct *async_queue;\r
109     u32 open_count;                     /*!<< device reference count. Not instance count */\r
110 \r
111     unsigned int freq_div;\r
112 \r
113     struct semaphore deint_mutex;\r
114 \r
115     struct clk *clk_coda7_axi;\r
116     struct clk *clk_coda7_cc;\r
117     struct clk *clk_coda7_apb;\r
118 \r
119     struct clk *clk_parent_axi;\r
120     struct clk *clk_parent_cc;\r
121     struct clk *clk_parent_apb;\r
122 \r
123     struct clk *clk_parent;\r
124     struct clk *clk_mm_i;\r
125 \r
126     unsigned int irq;\r
127 \r
128     //struct deint_fh *deint_fp;\r
129     struct device_node *dev_np;\r
130 } vpu_drv_context_t;\r
131 \r
132 /* To track the allocated memory buffer */\r
133 typedef struct vpudrv_buffer_pool_t {\r
134     struct list_head list;\r
135     struct vpudrv_buffer_t vb;\r
136     struct file *filp;\r
137 } vpudrv_buffer_pool_t;\r
138 \r
139 /* To track the instance index and buffer in instance pool */\r
140 typedef struct vpudrv_instanace_list_t {\r
141     struct list_head list;\r
142     unsigned long inst_idx;\r
143     unsigned long core_idx;\r
144     struct file *filp;\r
145 } vpudrv_instanace_list_t;\r
146 \r
147 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
148 \r
149 #define VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (62*1024*1024)\r
150 #define VPU_DRAM_PHYSICAL_BASE 0x86C00000\r
151 \r
152 #include "vmm.h"\r
153 static video_mm_t s_vmem;\r
154 static vpudrv_buffer_t s_video_memory = {0};\r
155 #else\r
156 #endif /*VPU_SUPPORT_RESERVED_VIDEO_MEMORY*/\r
157 \r
158 typedef struct vpudrv_instance_pool_t {\r
159     unsigned char codecInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE];\r
160     int vpu_instance_num;\r
161 } vpudrv_instance_pool_t;\r
162 \r
163 static int vpu_hw_reset(void);\r
164 \r
165 static void vpu_clk_disable(struct clk *clk);\r
166 static int vpu_clk_enable(struct clk *clk);\r
167 static struct clk *vpu_clk_get(struct device *dev);\r
168 static void vpu_clk_put(struct clk *clk);\r
169 \r
170 \r
171 /* end customer definition */\r
172 static vpudrv_buffer_t s_instance_pool = {0};\r
173 static vpudrv_buffer_t s_common_memory = {0};\r
174 static vpu_drv_context_t s_vpu_drv_context;\r
175 //static int s_vpu_major;\r
176 //static struct cdev s_vpu_cdev;\r
177 \r
178 static struct clk *s_vpu_clk;\r
179 \r
180 static int s_vpu_open_ref_count;\r
181 \r
182 #ifdef VPU_SUPPORT_ISR\r
183 static int s_vpu_irq = VPU_IRQ_NUM;\r
184 #endif\r
185 \r
186 static unsigned long s_vpu_reg_phy_addr = VPU_REG_BASE_ADDR;\r
187 \r
188 static void __iomem *s_vpu_reg_virt_addr;\r
189 \r
190 static int s_interrupt_flag;\r
191 static wait_queue_head_t s_interrupt_wait_q;\r
192 \r
193 static spinlock_t s_vpu_lock = __SPIN_LOCK_UNLOCKED(s_vpu_lock);\r
194 static DEFINE_SEMAPHORE(s_vpu_sem);\r
195 static struct list_head s_vbp_head = LIST_HEAD_INIT(s_vbp_head);\r
196 static struct list_head s_inst_list_head = LIST_HEAD_INIT(s_inst_list_head);\r
197 \r
198 \r
199 static vpu_bit_firmware_info_t s_bit_firmware_info[MAX_NUM_VPU_CORE];\r
200 static struct vpu_dev vpu_hw_dev;\r
201 \r
202 \r
203 #define BIT_BASE                    0x0000\r
204 #define BIT_CODE_RUN                (BIT_BASE + 0x000)\r
205 #define BIT_CODE_DOWN               (BIT_BASE + 0x004)\r
206 #define BIT_INT_CLEAR               (BIT_BASE + 0x00C)\r
207 #define BIT_INT_STS                 (BIT_BASE + 0x010)\r
208 #define BIT_CODE_RESET                          (BIT_BASE + 0x014)\r
209 #define BIT_BUSY_FLAG               (BIT_BASE + 0x160)\r
210 #define BIT_RUN_COMMAND             (BIT_BASE + 0x164)\r
211 #define BIT_RUN_INDEX               (BIT_BASE + 0x168)\r
212 #define BIT_RUN_COD_STD             (BIT_BASE + 0x16C)\r
213 #define BIT_CUR_PC                  (BIT_BASE + 0x018)\r
214 #define BIT_INT_REASON              (BIT_BASE + 0x174)\r
215 #define VPU_PRODUCT_CODE_REGISTER   (BIT_BASE + 0x1044)\r
216 \r
217 #if defined(CONFIG_ARCH_SCX35LT8)\r
218 #define REG_PMU_APB_CODEC_CFG REG_PMU_APB_PD_MM_CODEC_CFG\r
219 #define AUTO_SHUTDOWN_EN           BIT_PD_MM_CODEC_AUTO_SHUTDOWN_EN\r
220 #define FORCE_SHUTDOWN                BIT_PD_MM_CODEC_FORCE_SHUTDOWN\r
221 #else\r
222 #define REG_PMU_APB_CODEC_CFG REG_PMU_APB_PD_CODEC_TOP_CFG\r
223 #define AUTO_SHUTDOWN_EN           BIT_PD_CODEC_TOP_AUTO_SHUTDOWN_EN\r
224 #define FORCE_SHUTDOWN                BIT_PD_CODEC_TOP_FORCE_SHUTDOWN\r
225 #endif\r
226 \r
227 #ifdef CONFIG_PM\r
228 /* implement to power management functions */\r
229 static u32      s_vpu_reg_store[MAX_NUM_VPU_CORE][64];\r
230 static u32 s_run_index;\r
231 static u32 s_run_codstd;\r
232 #endif\r
233 \r
234 static int vpu_resume(struct platform_device *pdev);\r
235 static int vpu_suspend(struct platform_device *pdev, pm_message_t state);\r
236 static int vpu_set_mm_clk(void);\r
237 static int vpu_set_clk_by_register(void);\r
238 static int vpu_clk_free(vpu_drv_context_t* vpu_context);\r
239 static int vpu_power_on();\r
240 static int vpu_power_shutdown();\r
241 \r
242 #define ReadVpuRegister(addr)           *(volatile unsigned int *)(s_vpu_reg_virt_addr + s_bit_firmware_info[core].reg_base_offset + addr)\r
243 #define WriteVpuRegister(addr, val)     *(volatile unsigned int *)(s_vpu_reg_virt_addr + s_bit_firmware_info[core].reg_base_offset + addr) = (unsigned int)val\r
244 #define WriteVpu(addr, val)                     *(volatile unsigned int *)(addr) = (unsigned int)val\r
245 \r
246 #define DEFAULT_FREQ_DIV 0x0\r
247 \r
248 struct clock_name_map_t {\r
249     unsigned long freq;\r
250     char *name;\r
251 };\r
252 \r
253 static struct clock_name_map_t clock_coda7l_axi_map[] = {\r
254     {192000000,"clk_192m"},\r
255     {153600000,"clk_153m6"},\r
256     {128000000,"clk_128m"},\r
257     {76800000,"clk_76m8"}\r
258 };\r
259 \r
260 static struct clock_name_map_t clock_coda7l_cc_map[] = {\r
261     {192000000,"clk_192m"},\r
262     {153600000,"clk_153m6"},\r
263     {128000000,"clk_128m"},\r
264     {76800000,"clk_76m8"}\r
265 };\r
266 \r
267 static struct clock_name_map_t clock_coda7l_apb_map[] = {\r
268     {128000000,"clk_128m"},\r
269     {96000000,"clk_96m"},\r
270     {76800000,"clk_76m8"},\r
271     {26000000,"ext_26m"}\r
272 };\r
273 \r
274 static int max_freq_level = ARRAY_SIZE(clock_coda7l_axi_map);\r
275 \r
276 static char *vpu_get_clk_src_name(unsigned int freq_level, struct clock_name_map_t clk_map[])\r
277 {\r
278     if (freq_level >= max_freq_level ) {\r
279         printk(KERN_INFO "set freq_level to 0");\r
280         freq_level = 0;\r
281     }\r
282 \r
283     return clk_map[freq_level].name;\r
284 }\r
285 \r
286 static int find_vpu_freq_level(unsigned long freq, struct clock_name_map_t clk_map[])\r
287 {\r
288     int level = 0;\r
289     int i;\r
290     for (i = 0; i < max_freq_level; i++) {\r
291         if (clk_map[i].freq == freq) {\r
292             level = i;\r
293             break;\r
294         }\r
295     }\r
296     return level;\r
297 }\r
298 \r
299 static int vpu_power_on()\r
300 {\r
301     __raw_writel(AUTO_SHUTDOWN_EN | __raw_readl(REG_PMU_APB_CODEC_CFG), REG_PMU_APB_CODEC_CFG);\r
302     __raw_writel((~FORCE_SHUTDOWN) & __raw_readl(REG_PMU_APB_CODEC_CFG), REG_PMU_APB_CODEC_CFG);\r
303     return 0;\r
304 }\r
305 \r
306 static int vpu_power_shutdown()\r
307 {\r
308     __raw_writel(FORCE_SHUTDOWN | __raw_readl(REG_PMU_APB_CODEC_CFG), REG_PMU_APB_CODEC_CFG);\r
309     __raw_writel((~AUTO_SHUTDOWN_EN) & __raw_readl(REG_PMU_APB_CODEC_CFG), REG_PMU_APB_CODEC_CFG);\r
310     return 0;\r
311 }\r
312 \r
313 static int vpu_alloc_dma_buffer(vpudrv_buffer_t *vb)\r
314 {\r
315     if (!vb)\r
316         return -1;\r
317 \r
318 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
319     vb->phys_addr = (unsigned long)vmem_alloc(&s_vmem, vb->size, 0);\r
320     if ((unsigned long)vb->phys_addr  == (unsigned long)-1) {\r
321         vpu_loge("reserved Physical memory allocation error size=%d, base_addr=0x%x, mem_size=%d\n", vb->size, (int)s_vmem.base_addr, (int)s_vmem.mem_size);\r
322         return -1;\r
323     }\r
324 \r
325     vb->base = (unsigned long)(s_video_memory.base + (vb->phys_addr - s_video_memory.phys_addr));\r
326 #else\r
327     vb->base = (unsigned long)dma_alloc_coherent(NULL, PAGE_ALIGN(vb->size), (dma_addr_t *) (&vb->phys_addr), GFP_DMA | GFP_KERNEL);\r
328     if ((void *)(vb->base) == NULL)     {\r
329         vpu_loge("dynamic Physical memory allocation error size=%d\n", vb->size);\r
330         return -1;\r
331     }\r
332 #endif\r
333 \r
334 \r
335     return 0;\r
336 }\r
337 \r
338 static void vpu_free_dma_buffer(vpudrv_buffer_t *vb)\r
339 {\r
340     if (!vb)\r
341         return;\r
342 \r
343 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
344     if (vb->base)\r
345         vmem_free(&s_vmem, vb->phys_addr, 0);\r
346 #else\r
347     if (vb->base)\r
348         dma_free_coherent(0, PAGE_ALIGN(vb->size), (void *)vb->base, vb->phys_addr);\r
349 #endif\r
350 \r
351 }\r
352 \r
353 static int vpu_free_instances(struct file *filp)\r
354 {\r
355     vpudrv_instanace_list_t *vil, *n;\r
356     vpudrv_instance_pool_t *vip;\r
357     unsigned char *vip_base;\r
358     int instance_pool_size_per_core;\r
359     unsigned char *vdi_mutexes_base;\r
360     const int PTHREAD_MUTEX_T_DESTROY_VALUE = 0xdead10cc;\r
361 \r
362     vpu_logd("vpu_free_instances inter. sizeof(vpudrv_instance_pool_t)=%d \n", sizeof(vpudrv_instance_pool_t));\r
363 \r
364     instance_pool_size_per_core = (s_instance_pool.size/MAX_NUM_VPU_CORE); /* s_instance_pool.size  assigned to the size of all core once call VDI_IOCTL_GET_INSTANCE_POOL by user. */\r
365 \r
366     list_for_each_entry_safe(vil, n, &s_inst_list_head, list)\r
367     {\r
368         if (vil->filp == filp) {\r
369             s_vpu_open_ref_count--;\r
370             vip_base = (unsigned char *)(s_instance_pool.base + (instance_pool_size_per_core*vil->core_idx));\r
371             vpu_logd("vpu_free_instances detect instance crash\n");\r
372             vpu_logd("instIdx=%d, coreIdx=%d, vip_base=%p, instance_pool_size_per_core=%d\n", (int)vil->inst_idx, (int)vil->core_idx, vip_base, (int)instance_pool_size_per_core);\r
373             vip = (vpudrv_instance_pool_t *)vip_base;\r
374             if (vip) {\r
375                 memset(&vip->codecInstPool[vil->inst_idx], 0x00, 4);    /* only first 4 byte is key point to free the corresponding instance. */\r
376                 vip->vpu_instance_num = s_vpu_open_ref_count;\r
377 #define PTHREAD_MUTEX_T_HANDLE_SIZE 4\r
378                 vdi_mutexes_base = (unsigned char *)(vip_base + (instance_pool_size_per_core - PTHREAD_MUTEX_T_HANDLE_SIZE*4));\r
379                 vpu_logd("vpu_free_instances : force to destroy vdi_mutexes_base=%p in userspace, vip->vpu_instance_num=%d\n",\r
380                          vdi_mutexes_base, vip->vpu_instance_num);\r
381                 if (vdi_mutexes_base) {\r
382                     int i;\r
383                     for (i=0; i < 4; i++) {\r
384                         memcpy(vdi_mutexes_base, &PTHREAD_MUTEX_T_DESTROY_VALUE, PTHREAD_MUTEX_T_HANDLE_SIZE);\r
385                         vdi_mutexes_base += PTHREAD_MUTEX_T_HANDLE_SIZE;\r
386                     }\r
387                 }\r
388             }\r
389             list_del(&vil->list);\r
390             kfree(vil);\r
391         }\r
392     }\r
393 \r
394     return 1;\r
395 }\r
396 \r
397 static int vpu_free_buffers(struct file *filp)\r
398 {\r
399     vpudrv_buffer_pool_t *pool, *n;\r
400     vpudrv_buffer_t vb;\r
401 \r
402     vpu_logd("vpu_free_buffers\n");\r
403 \r
404     list_for_each_entry_safe(pool, n, &s_vbp_head, list)\r
405     {\r
406         if (pool->filp == filp) {\r
407             vb = pool->vb;\r
408             if (vb.base) {\r
409                 vpu_free_dma_buffer(&vb);\r
410                 list_del(&pool->list);\r
411                 kfree(pool);\r
412             }\r
413         }\r
414 \r
415     }\r
416 \r
417     return 0;\r
418 }\r
419 \r
420 static irqreturn_t vpu_irq_handler(int irq, void *dev_id)\r
421 {\r
422     vpu_drv_context_t *dev = (vpu_drv_context_t *)dev_id;\r
423 \r
424     /* this can be removed. it also work in VPU_WaitInterrupt of API function */\r
425     int core;\r
426 \r
427     if (s_vpu_drv_context.open_count <= 0)\r
428     {\r
429         //printk(KERN_ERR "This interrupt signal is not for VPU\n");\r
430         return IRQ_NONE;\r
431     }\r
432 \r
433 #ifdef VPU_IRQ_CONTROL\r
434     disable_irq_nosync(s_vpu_irq);\r
435 #endif\r
436 \r
437     for (core = 0; core < MAX_NUM_VPU_CORE; core++)     {\r
438         /*it means that we didn't get an information the current core from API layer. No core activated.*/\r
439         if (s_bit_firmware_info[core].size == 0)\r
440             continue;\r
441 \r
442         if (ReadVpuRegister(BIT_INT_STS))\r
443         {\r
444             WriteVpuRegister(BIT_INT_CLEAR, 0x1);\r
445         }\r
446         else\r
447         {\r
448             return  IRQ_NONE;\r
449         }\r
450     }\r
451 \r
452     if (dev->async_queue)\r
453         kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to user space */\r
454 \r
455     s_interrupt_flag = 1;\r
456 \r
457     wake_up_interruptible(&s_interrupt_wait_q);\r
458     return IRQ_HANDLED;\r
459 }\r
460 \r
461 static int vpu_open(struct inode *inode, struct file *filp)\r
462 {\r
463     int ret = 0;\r
464 \r
465     spin_lock(&s_vpu_lock);\r
466     vpu_logi("[VPUDRV] vpu_open\n");\r
467 \r
468     s_vpu_drv_context.open_count++;\r
469     filp->private_data = (void *)(&s_vpu_drv_context);\r
470 \r
471     vpu_power_on();\r
472     ret = vpu_set_mm_clk();\r
473 \r
474 #if 0\r
475     vpu_logi("[VPUDRV] REG_PMU_APB_PD_MM_TOP_CFG : 0x%x\n", __raw_readl(REG_PMU_APB_PD_MM_TOP_CFG));\r
476     vpu_logi("[VPUDRV] REG_AON_APB_APB_EB0 : 0x%x\n", __raw_readl(REG_AON_APB_APB_EB0));\r
477     vpu_logi("[VPUDRV] REG_AON_APB_APB_EB1 : 0x%x\n", __raw_readl(REG_AON_APB_APB_EB1));\r
478     vpu_logi("[VPUDRV] REG_CODEC_AHB_CLOCK_SEL : 0x%x\n", __raw_readl(REG_CODEC_AHB_CLOCK_SEL));\r
479     vpu_logi("[VPUDRV] REG_CODEC_AHB_CKG_ENABLE : 0x%x\n", __raw_readl(REG_CODEC_AHB_CKG_ENABLE));\r
480 #endif\r
481 \r
482 #if defined(CONFIG_SPRD_IOMMU)\r
483     sprd_iommu_module_enable(IOMMU_MM);\r
484 #endif\r
485 \r
486     spin_unlock(&s_vpu_lock);\r
487 \r
488     return ret;\r
489 }\r
490 \r
491 /*static int vpu_ioctl(struct inode *inode, struct file *filp, u_int cmd, u_long arg) // for kernel 2.6.9 of C&M*/\r
492 static long vpu_ioctl(struct file *filp, u_int cmd, u_long arg)\r
493 {\r
494     int ret = 0;\r
495     switch (cmd) {\r
496     case VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY:\r
497     {\r
498         vpudrv_buffer_pool_t *vbp;\r
499 \r
500         down(&s_vpu_sem);\r
501 \r
502         vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);\r
503         if (!vbp) {\r
504             up(&s_vpu_sem);\r
505             return -ENOMEM;\r
506         }\r
507 \r
508         ret = copy_from_user(&(vbp->vb), (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t));\r
509         if (ret) {\r
510             kfree(vbp);\r
511             up(&s_vpu_sem);\r
512             return -EFAULT;\r
513         }\r
514 \r
515         ret = vpu_alloc_dma_buffer(&(vbp->vb));\r
516         if (ret == -1) {\r
517             ret = -ENOMEM;\r
518             kfree(vbp);\r
519             up(&s_vpu_sem);\r
520             break;\r
521         }\r
522         ret = copy_to_user((void __user *)arg, &(vbp->vb), sizeof(vpudrv_buffer_t));\r
523         if (ret) {\r
524             kfree(vbp);\r
525             ret = -EFAULT;\r
526             up(&s_vpu_sem);\r
527             break;\r
528         }\r
529 \r
530         vbp->filp = filp;\r
531         spin_lock(&s_vpu_lock);\r
532         list_add(&vbp->list, &s_vbp_head);\r
533         spin_unlock(&s_vpu_lock);\r
534 \r
535         up(&s_vpu_sem);\r
536     }\r
537     break;\r
538     case VDI_IOCTL_FREE_PHYSICALMEMORY:\r
539     {\r
540         vpudrv_buffer_pool_t *vbp, *n;\r
541         vpudrv_buffer_t vb;\r
542 \r
543         down(&s_vpu_sem);\r
544 \r
545         ret = copy_from_user(&vb, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t));\r
546         if (ret) {\r
547             up(&s_vpu_sem);\r
548             return -EACCES;\r
549         }\r
550 \r
551         if (vb.base)\r
552             vpu_free_dma_buffer(&vb);\r
553 \r
554         spin_lock(&s_vpu_lock);\r
555         list_for_each_entry_safe(vbp, n, &s_vbp_head, list)\r
556         {\r
557             if (vbp->vb.base == vb.base) {\r
558                 list_del(&vbp->list);\r
559                 kfree(vbp);\r
560                 break;\r
561             }\r
562         }\r
563         spin_unlock(&s_vpu_lock);\r
564 \r
565         up(&s_vpu_sem);\r
566 \r
567     }\r
568     break;\r
569     case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO:\r
570     {\r
571 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
572         if (s_video_memory.base != 0) {\r
573             ret = copy_to_user((void __user *)arg, &s_video_memory, sizeof(vpudrv_buffer_t));\r
574             if (ret != 0)\r
575                 ret = -EFAULT;\r
576         } else {\r
577             ret = -EFAULT;\r
578         }\r
579 #endif\r
580     }\r
581     break;\r
582 \r
583     case VDI_IOCTL_WAIT_INTERRUPT:\r
584     {\r
585         u32 timeout = (u32) arg;\r
586 \r
587         ret = wait_event_interruptible_timeout(s_interrupt_wait_q, s_interrupt_flag != 0, msecs_to_jiffies(timeout));\r
588         if (ret == 0) {\r
589             ret = -ETIME;\r
590             break;\r
591         }\r
592 \r
593         if (signal_pending(current)) {\r
594             ret = -ERESTARTSYS;\r
595             break;\r
596         }\r
597 \r
598         ret = 0;\r
599         s_interrupt_flag = 0;\r
600 #ifdef VPU_IRQ_CONTROL\r
601         enable_irq(s_vpu_irq);\r
602 #endif\r
603     }\r
604     break;\r
605 \r
606     case VDI_IOCTL_SET_CLOCK_GATE:\r
607     {\r
608         u32 clkgate;\r
609 \r
610         //vpu_logi("[VPUDRV] VDI_IOCTL_SET_CLOCK_GATE s_vpu_clk = %x\n", s_vpu_clk);\r
611 \r
612         if (get_user(clkgate, (u32 __user *) arg))\r
613             return -EFAULT;\r
614 #ifdef VPU_SUPPORT_CLOCK_CONTROL\r
615         if (clkgate)\r
616             vpu_clk_enable(s_vpu_clk);\r
617         else\r
618             vpu_clk_disable(s_vpu_clk);\r
619 #endif\r
620 \r
621         //vpu_logi("[VPUDRV] VDI_IOCTL_SET_CLOCK_GATE sucessfully \n");\r
622 \r
623     }\r
624     break;\r
625     case VDI_IOCTL_GET_INSTANCE_POOL:\r
626     {\r
627         down(&s_vpu_sem);\r
628 \r
629         vpu_logi("[VPUDRV] VDI_IOCTL_GET_INSTANCE_POOL\n");\r
630 \r
631         if (s_instance_pool.base != 0) {\r
632             ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t));\r
633             if (ret != 0)\r
634                 ret = -EFAULT;\r
635         } else {\r
636             ret = copy_from_user(&s_instance_pool, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t));\r
637             if (ret == 0) {\r
638                 if (vpu_alloc_dma_buffer(&s_instance_pool) != -1)\r
639                 {\r
640                     vpu_logi("[VPUDRV] vpu_alloc_dma_buffer sucessfully\n");\r
641                     memset((void *)s_instance_pool.base, 0x0, s_instance_pool.size); /*clearing memory*/\r
642                     ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t));\r
643                     if (ret == 0) {\r
644                         /* success to get memory for instance pool */\r
645                         up(&s_vpu_sem);\r
646                         break;\r
647                     }\r
648                 }\r
649 \r
650             }\r
651             ret = -EFAULT;\r
652         }\r
653 \r
654         up(&s_vpu_sem);\r
655     }\r
656     break;\r
657     case VDI_IOCTL_GET_COMMON_MEMORY:\r
658     {\r
659         if (s_common_memory.base != 0) {\r
660             ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t));\r
661             if (ret != 0)\r
662                 ret = -EFAULT;\r
663         } else {\r
664             ret = copy_from_user(&s_common_memory, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t));\r
665             if (ret == 0) {\r
666                 if (vpu_alloc_dma_buffer(&s_common_memory) != -1) {\r
667                     ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t));\r
668                     if (ret == 0) {\r
669                         /* success to get memory for common memory */\r
670                         break;\r
671                     }\r
672                 }\r
673             }\r
674 \r
675             ret = -EFAULT;\r
676         }\r
677     }\r
678     break;\r
679     case VDI_IOCTL_OPEN_INSTANCE:\r
680     {\r
681         vpudrv_inst_info_t inst_info;\r
682         vpudrv_instanace_list_t *vil, *n;\r
683 \r
684         vil = kzalloc(sizeof(*vil), GFP_KERNEL);\r
685         if (!vil)\r
686             return -ENOMEM;\r
687 \r
688         if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t))) {\r
689             kfree(vil);\r
690             return -EFAULT;\r
691         }\r
692 \r
693         vil->inst_idx = inst_info.inst_idx;\r
694         vil->core_idx = inst_info.core_idx;\r
695         vil->filp = filp;\r
696         spin_lock(&s_vpu_lock);\r
697         list_add(&vil->list, &s_inst_list_head);\r
698 \r
699         inst_info.inst_open_count = 0; /* counting the current open instance number */\r
700         list_for_each_entry_safe(vil, n, &s_inst_list_head, list)\r
701         {\r
702             if (vil->core_idx == inst_info.core_idx)\r
703                 inst_info.inst_open_count++;\r
704         }\r
705         spin_unlock(&s_vpu_lock);\r
706         s_vpu_open_ref_count++; /* flag just for that vpu is in opened or closed */\r
707 \r
708         if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t))) {\r
709             kfree(vil);\r
710             return -EFAULT;\r
711         }\r
712 \r
713         vpu_logd("[VPUDRV] VDI_IOCTL_OPEN_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count);\r
714     }\r
715     break;\r
716     case VDI_IOCTL_CLOSE_INSTANCE:\r
717     {\r
718         vpudrv_inst_info_t inst_info;\r
719         vpudrv_instanace_list_t *vil, *n;\r
720 \r
721         if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t)))\r
722             return -EFAULT;\r
723         spin_lock(&s_vpu_lock);\r
724         list_for_each_entry_safe(vil, n, &s_inst_list_head, list)\r
725         {\r
726             if (vil->inst_idx == inst_info.inst_idx && vil->core_idx == inst_info.core_idx) {\r
727                 list_del(&vil->list);\r
728                 kfree(vil);\r
729                 break;\r
730             }\r
731         }\r
732 \r
733         inst_info.inst_open_count = 0; /* counting the current open instance number */\r
734         list_for_each_entry_safe(vil, n, &s_inst_list_head, list)\r
735         {\r
736             if (vil->core_idx == inst_info.core_idx)\r
737                 inst_info.inst_open_count++;\r
738         }\r
739         spin_unlock(&s_vpu_lock);\r
740         s_vpu_open_ref_count--; /* flag just for that vpu is in opened or closed */\r
741 \r
742         if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t)))\r
743             return -EFAULT;\r
744 \r
745         vpu_logd("[VPUDRV] VDI_IOCTL_CLOSE_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count);\r
746     }\r
747     break;\r
748     case VDI_IOCTL_GET_INSTANCE_NUM:\r
749     {\r
750         vpudrv_inst_info_t inst_info;\r
751         vpudrv_instanace_list_t *vil, *n;\r
752 \r
753         ret = copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t));\r
754         if (ret != 0)\r
755             break;\r
756 \r
757         inst_info.inst_open_count = 0;\r
758         spin_lock(&s_vpu_lock);\r
759         list_for_each_entry_safe(vil, n, &s_inst_list_head, list)\r
760         {\r
761             if (vil->core_idx == inst_info.core_idx)\r
762                 inst_info.inst_open_count++;\r
763         }\r
764         spin_unlock(&s_vpu_lock);\r
765         ret = copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t));\r
766 \r
767         vpu_logd("[VPUDRV] VDI_IOCTL_GET_INSTANCE_NUM core_idx=%d, inst_idx=%d, open_count=%d\n", (int)inst_info.core_idx, (int)inst_info.inst_idx, inst_info.inst_open_count);\r
768 \r
769     }\r
770     break;\r
771     case VDI_IOCTL_RESET:\r
772     {\r
773         vpu_hw_reset();\r
774     }\r
775     break;\r
776     default:\r
777     {\r
778         printk(KERN_ERR "[VPUDRV] No such IOCTL, cmd is %d\n", cmd);\r
779     }\r
780     break;\r
781     }\r
782     return ret;\r
783 }\r
784 \r
785 \r
786 static ssize_t vpu_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)\r
787 {\r
788 \r
789     return -1;\r
790 }\r
791 \r
792 static ssize_t vpu_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)\r
793 {\r
794 \r
795     /* vpu_logi("[VPUDRV] vpu_write len=%d\n", (int)len); */\r
796     if (!buf) {\r
797         vpu_loge("vpu_write buf = NULL error \n");\r
798         return -EFAULT;\r
799     }\r
800 \r
801     if (len == sizeof(vpu_bit_firmware_info_t)) {\r
802         vpu_bit_firmware_info_t *bit_firmware_info;\r
803 \r
804         bit_firmware_info = kzalloc(sizeof(vpu_bit_firmware_info_t), GFP_KERNEL);\r
805         if (!bit_firmware_info) {\r
806             vpu_loge("vpu_write  bit_firmware_info allocation error \n");\r
807             return -EFAULT;\r
808         }\r
809 \r
810         if (copy_from_user(bit_firmware_info, buf, len)) {\r
811             vpu_loge("vpu_write copy_from_user error for bit_firmware_info\n");\r
812             kfree(bit_firmware_info);\r
813             return -EFAULT;\r
814         }\r
815 \r
816         if (bit_firmware_info->size == sizeof(vpu_bit_firmware_info_t)) {\r
817             vpu_logd("vpu_write set bit_firmware_info coreIdx=0x%x, reg_base_offset=0x%x size=0x%x, bit_code[0]=0x%x\n", bit_firmware_info->core_idx, (int)bit_firmware_info->reg_base_offset, bit_firmware_info->size, bit_firmware_info->bit_code[0]);\r
818 \r
819             if (bit_firmware_info->core_idx > MAX_NUM_VPU_CORE) {\r
820                 vpu_loge("vpu_write coreIdx[%d] is exceeded than MAX_NUM_VPU_CORE[%d]\n", bit_firmware_info->core_idx, MAX_NUM_VPU_CORE);\r
821                 kfree(bit_firmware_info);\r
822                 return -ENODEV;\r
823             }\r
824 \r
825             memcpy((void *)&s_bit_firmware_info[bit_firmware_info->core_idx], bit_firmware_info, sizeof(vpu_bit_firmware_info_t));\r
826             kfree(bit_firmware_info);\r
827             return len;\r
828         }\r
829 \r
830         kfree(bit_firmware_info);\r
831     }\r
832 \r
833 \r
834 \r
835 \r
836     return -1;\r
837 }\r
838 \r
839 static int vpu_release(struct inode *inode, struct file *filp)\r
840 {\r
841     int reg_addr;\r
842 \r
843     spin_lock(&s_vpu_lock);\r
844 \r
845     vpu_logi("[VPUDRV] vpu_release, open_count= %d\n", s_vpu_drv_context.open_count);\r
846 \r
847     /* found and free the not handled buffer by user applications */\r
848     vpu_free_buffers(filp);\r
849 \r
850     /* found and free the not closed instance by user applications */\r
851     vpu_free_instances(filp);\r
852     s_vpu_drv_context.open_count--;\r
853     if (s_vpu_drv_context.open_count == 0) {\r
854         if (s_instance_pool.base) {\r
855             vpu_logi("[VPUDRV] free instance pool\n");\r
856             vpu_free_dma_buffer(&s_instance_pool);\r
857             s_instance_pool.base = 0;\r
858         }\r
859 \r
860         if (s_common_memory.base) {\r
861             vpu_logi("[VPUDRV] free common memory\n");\r
862             vpu_free_dma_buffer(&s_common_memory);\r
863             s_common_memory.base = 0;\r
864         }\r
865     }\r
866 \r
867     vpu_clk_free(&s_vpu_drv_context);\r
868 \r
869     if(s_vpu_drv_context.open_count == 0) {\r
870         vpu_logi("%s vpu_power_shutdown\n", __func__);\r
871         vpu_power_shutdown();\r
872     }\r
873 \r
874 #if defined(CONFIG_SPRD_IOMMU)\r
875     sprd_iommu_module_disable(IOMMU_MM);\r
876 #endif\r
877 \r
878     spin_unlock(&s_vpu_lock);\r
879 \r
880 \r
881 \r
882     return 0;\r
883 }\r
884 \r
885 \r
886 static int vpu_fasync(int fd, struct file *filp, int mode)\r
887 {\r
888     struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)filp->private_data;\r
889     return fasync_helper(fd, filp, mode, &dev->async_queue);\r
890 }\r
891 \r
892 \r
893 static int vpu_map_to_register(struct file *fp, struct vm_area_struct *vm)\r
894 {\r
895     unsigned long pfn;\r
896 \r
897     printk("[%s]\n", __FUNCTION__);\r
898 \r
899     vm->vm_flags |= VM_IO | VM_RESERVED;\r
900     vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);\r
901     pfn = s_vpu_reg_phy_addr >> PAGE_SHIFT;\r
902 \r
903     return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0;\r
904 }\r
905 \r
906 static int vpu_map_to_physical_memory(struct file *fp, struct vm_area_struct *vm)\r
907 {\r
908     printk("[%s]\n", __FUNCTION__);\r
909 \r
910     vm->vm_flags |= VM_IO | VM_RESERVED;\r
911     vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);\r
912 \r
913     return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0;\r
914 }\r
915 static int vpu_map_to_instance_pool_memory(struct file *fp, struct vm_area_struct *vm)\r
916 {\r
917     printk("[%s]\n", __FUNCTION__);\r
918 \r
919     return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0;\r
920 }\r
921 \r
922 /*!\r
923  * @brief memory map interface for vpu file operation\r
924  * @return  0 on success or negative error code on error\r
925  */\r
926 static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)\r
927 {\r
928     printk("[%s],  vm_pgoff = %ld \n", __FUNCTION__, vm->vm_pgoff);\r
929 \r
930     if (vm->vm_pgoff) {\r
931         if (vm->vm_pgoff == (s_instance_pool.phys_addr>>PAGE_SHIFT))\r
932             return vpu_map_to_instance_pool_memory(fp, vm);\r
933 \r
934         return vpu_map_to_physical_memory(fp, vm);\r
935     } else {\r
936         return vpu_map_to_register(fp, vm);\r
937     }\r
938 }\r
939 \r
940 struct file_operations vpu_fops = {\r
941     .owner = THIS_MODULE,\r
942     .open = vpu_open,\r
943     .read = vpu_read,\r
944     .write = vpu_write,\r
945     .unlocked_ioctl = vpu_ioctl,\r
946     .release = vpu_release,\r
947     .fasync = vpu_fasync,\r
948     .mmap = vpu_mmap,\r
949 #ifdef CONFIG_COMPAT\r
950     .compat_ioctl   = vpu_ioctl,\r
951 #endif\r
952 };\r
953 \r
954 static struct miscdevice vpu_dev = {\r
955     .minor   = VPU_MINOR,\r
956     .name   = "sprd_coda7l",\r
957     .fops   = &vpu_fops,\r
958 };\r
959 \r
960 \r
961 #ifdef CONFIG_OF\r
962 static const struct of_device_id  of_match_table_coda7l[] = {\r
963     { .compatible = "sprd,sprd_coda7l", },\r
964     { },\r
965 };\r
966 \r
967 static int vpu_parse_dt(struct device *dev)\r
968 {\r
969     struct device_node *np = dev->of_node;\r
970     struct resource res;\r
971     int ret;\r
972 \r
973     ret = of_address_to_resource(np, 0, &res);\r
974     if(ret < 0) {\r
975         dev_err(dev, "no reg of property specified\n");\r
976         printk(KERN_ERR "vsp: failed to parse_dt!\n");\r
977         return -EINVAL;\r
978     }\r
979 \r
980     s_vpu_reg_phy_addr = res.start;\r
981     s_vpu_reg_virt_addr = ioremap_nocache(res.start, resource_size(&res));\r
982     if(!s_vpu_reg_virt_addr)\r
983         BUG();\r
984 \r
985     s_vpu_drv_context.irq = irq_of_parse_and_map(np, 0);\r
986     s_vpu_drv_context.dev_np = np;\r
987 \r
988     printk(KERN_INFO "vsp_parse_dt s_vpu_drv_context.irq = %d !\n", s_vpu_drv_context.irq);\r
989 \r
990     printk(KERN_INFO "deint_parse_dt ,  SPRD_VPP_PHYS = %p, SPRD_VPP_BASE = %p\n", (void*)s_vpu_reg_phy_addr, (void*)s_vpu_reg_virt_addr);\r
991 \r
992     return 0;\r
993 }\r
994 #else\r
995 static int  vpu_parse_dt(\r
996     struct device *dev)\r
997 {\r
998     //vsp_hw_dev.irq = IRQ_VSP_INT;\r
999     return 0;\r
1000 }\r
1001 #endif\r
1002 \r
1003 \r
1004 static int vpu_probe(struct platform_device *pdev)\r
1005 {\r
1006     int err = 0;\r
1007     int ret;\r
1008     int reg_addr;\r
1009     struct resource *res = NULL;\r
1010 \r
1011     vpu_logi("[VPUDRV] vpu_probe\n");\r
1012 \r
1013 #ifdef CONFIG_OF\r
1014     if (pdev->dev.of_node) {\r
1015         ret = vpu_parse_dt(&pdev->dev);\r
1016     }\r
1017 #else\r
1018     ret = vpu_parse_dt(&pdev->dev);\r
1019 #endif\r
1020 \r
1021     s_vpu_drv_context.freq_div = DEFAULT_FREQ_DIV;\r
1022     s_vpu_drv_context.clk_mm_i= NULL;\r
1023     s_vpu_drv_context.clk_parent_axi= NULL;\r
1024     s_vpu_drv_context.clk_parent_cc= NULL;\r
1025     s_vpu_drv_context.clk_parent_apb= NULL;\r
1026     s_vpu_drv_context.clk_coda7_apb= NULL;\r
1027     s_vpu_drv_context.clk_coda7_axi= NULL;\r
1028     s_vpu_drv_context.clk_coda7_cc= NULL;\r
1029 \r
1030     ret = misc_register(&vpu_dev);\r
1031     if (ret) {\r
1032         printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n",\r
1033                VPU_MINOR, ret);\r
1034         goto ERROR_PROVE_DEVICE;\r
1035     }\r
1036 \r
1037 #ifdef VPU_SUPPORT_ISR\r
1038     if (pdev)\r
1039         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);\r
1040     if (res) {// if platform driver is implemented\r
1041         s_vpu_irq = res->start;\r
1042         vpu_logi("[VPUDRV] : vpu irq number get from platform driver irq=0x%x\n", s_vpu_irq);\r
1043     } else {\r
1044         vpu_logi("[VPUDRV] : vpu irq number get from defined value irq=0x%x\n", s_vpu_irq);\r
1045     }\r
1046 \r
1047 \r
1048     err = request_irq(s_vpu_irq, vpu_irq_handler, IRQF_SHARED, "VPU_CODEC_IRQ", (void *)(&s_vpu_drv_context));\r
1049     if (err) {\r
1050         printk(KERN_ERR "[VPUDRV] :  fail to register interrupt handler\n");\r
1051         goto ERROR_PROVE_DEVICE;\r
1052     }\r
1053 #endif\r
1054 \r
1055 \r
1056 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
1057     s_video_memory.size = VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE;\r
1058     s_video_memory.phys_addr = VPU_DRAM_PHYSICAL_BASE;\r
1059     s_video_memory.base = (unsigned long)ioremap(s_video_memory.phys_addr, PAGE_ALIGN(s_video_memory.size));\r
1060     if (!s_video_memory.base) {\r
1061         printk(KERN_ERR "[VPUDRV] :  fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n",\r
1062                (int)s_video_memory.phys_addr, (int)s_video_memory.base, (int)s_video_memory.size);\r
1063         goto ERROR_PROVE_DEVICE;\r
1064     }\r
1065 \r
1066     if (vmem_init(&s_vmem, s_video_memory.phys_addr, s_video_memory.size) < 0) {\r
1067         printk(KERN_ERR "[VPUDRV] :  fail to init vmem system\n");\r
1068         goto ERROR_PROVE_DEVICE;\r
1069     }\r
1070     vpu_logi("[VPUDRV] success to probe vpu device with reserved video memory phys_addr=0x%x, base = 0x%x\n",\r
1071              (int) s_video_memory.phys_addr, (int)s_video_memory.base);\r
1072 #else\r
1073     vpu_logi("[VPUDRV] success to probe vpu device with non reserved video memory\n");\r
1074 #endif\r
1075 \r
1076     return 0;\r
1077 \r
1078 \r
1079 ERROR_PROVE_DEVICE:\r
1080 \r
1081     misc_deregister(&vpu_dev);\r
1082 \r
1083     if (s_vpu_reg_virt_addr)\r
1084         iounmap(s_vpu_reg_virt_addr);\r
1085 \r
1086     return err;\r
1087 }\r
1088 \r
1089 static int vpu_remove(struct platform_device *pdev)\r
1090 {\r
1091     vpu_logd("vpu_remove\n");\r
1092 #ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER\r
1093 \r
1094     misc_deregister(&vpu_dev);\r
1095 \r
1096     if (s_instance_pool.base) {\r
1097         vpu_free_dma_buffer(&s_instance_pool);\r
1098         s_instance_pool.base = 0;\r
1099     }\r
1100 \r
1101     if (s_common_memory.base) {\r
1102         vpu_free_dma_buffer(&s_common_memory);\r
1103         s_common_memory.base = 0;\r
1104     }\r
1105 \r
1106 \r
1107 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
1108     if (s_video_memory.base) {\r
1109         iounmap((void *)s_video_memory.base);\r
1110         s_video_memory.base = 0;\r
1111 \r
1112         vmem_exit(&s_vmem);\r
1113     }\r
1114 #endif\r
1115 \r
1116 #ifdef VPU_SUPPORT_ISR\r
1117     if (s_vpu_drv_context.irq)\r
1118         free_irq(s_vpu_drv_context.irq, &s_vpu_drv_context);\r
1119 #endif\r
1120 \r
1121     vpu_clk_put(s_vpu_clk);\r
1122 \r
1123 \r
1124 \r
1125 #endif /*VPU_SUPPORT_PLATFORM_DRIVER_REGISTER*/\r
1126 \r
1127 \r
1128     return 0;\r
1129 }\r
1130 \r
1131 #ifdef CONFIG_PM\r
1132 static int vpu_suspend(struct platform_device *pdev, pm_message_t state)\r
1133 {\r
1134     vpu_logd("vpu_suspend\n");\r
1135     return 0;\r
1136 }\r
1137 static int vpu_resume(struct platform_device *pdev)\r
1138 {\r
1139     vpu_logd("vpu_resume\n");\r
1140     return 0;\r
1141 }\r
1142 #else\r
1143 #define vpu_suspend     NULL\r
1144 #define vpu_resume      NULL\r
1145 #endif                          /* !CONFIG_PM */\r
1146 \r
1147 \r
1148 static struct platform_driver vpu_driver = {\r
1149     .probe = vpu_probe,\r
1150     .remove = vpu_remove,\r
1151     .suspend = vpu_suspend,\r
1152     .resume = vpu_resume,\r
1153     .driver   = {\r
1154         .owner = THIS_MODULE,\r
1155         .name = "sprd_coda7l",\r
1156 #ifdef CONFIG_OF\r
1157         .of_match_table = of_match_ptr(of_match_table_coda7l) ,\r
1158 #endif\r
1159     },\r
1160 };\r
1161 \r
1162 static int __init vpu_init(void)\r
1163 {\r
1164     int res = 0;\r
1165 \r
1166     vpu_logd("vpu_init, REG_AON_APB_BOND_OPT0 = 0x%x\n", __raw_readl(REG_AON_APB_BOND_OPT0));\r
1167 \r
1168     if(__raw_readl(REG_AON_APB_BOND_OPT0) & (1<<12)) {\r
1169         return 0;\r
1170     }\r
1171 \r
1172     init_waitqueue_head(&s_interrupt_wait_q);\r
1173     s_common_memory.base = 0;\r
1174     s_instance_pool.base = 0;\r
1175 #ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER\r
1176     res = platform_driver_register(&vpu_driver);\r
1177 #else\r
1178     res = platform_driver_register(&vpu_driver);\r
1179     res = vpu_probe(NULL);\r
1180 #endif\r
1181     vpu_power_shutdown();\r
1182     vpu_logd("end vpu_init result=0x%x\n", res);\r
1183 \r
1184     return res;\r
1185 }\r
1186 \r
1187 static void __exit vpu_exit(void)\r
1188 {\r
1189 #ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER\r
1190     vpu_logd("vpu_exit\n");\r
1191 \r
1192     if(__raw_readl(REG_AON_APB_BOND_OPT0) & (1<<12)) {\r
1193         return ;\r
1194     }\r
1195 \r
1196     platform_driver_unregister(&vpu_driver);\r
1197 \r
1198 #else\r
1199 \r
1200     vpu_clk_put(s_vpu_clk);\r
1201 \r
1202     if (s_instance_pool.base) {\r
1203         vpu_free_dma_buffer(&s_instance_pool);\r
1204         s_instance_pool.base = 0;\r
1205     }\r
1206 \r
1207     if (s_common_memory.base) {\r
1208         vpu_free_dma_buffer(&s_common_memory);\r
1209         s_common_memory.base = 0;\r
1210     }\r
1211 \r
1212 #ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY\r
1213     if (s_video_memory.base) {\r
1214         iounmap((void *)s_video_memory.base);\r
1215         s_video_memory.base = 0;\r
1216 \r
1217         vmem_exit(&s_vmem);\r
1218     }\r
1219 #endif\r
1220 \r
1221     if (s_vpu_major > 0) {\r
1222         cdev_del(&s_vpu_cdev);\r
1223         unregister_chrdev_region(s_vpu_major, 1);\r
1224         s_vpu_major = 0;\r
1225     }\r
1226 \r
1227 #ifdef VPU_SUPPORT_ISR\r
1228     if (s_vpu_irq)\r
1229         free_irq(s_vpu_irq, &s_vpu_drv_context);\r
1230 #endif\r
1231 \r
1232 #endif\r
1233 \r
1234     return;\r
1235 }\r
1236 \r
1237 \r
1238 \r
1239 MODULE_AUTHOR("A customer using C&M VPU, Inc.");\r
1240 MODULE_DESCRIPTION("VPU linux driver");\r
1241 MODULE_LICENSE("GPL");\r
1242 \r
1243 module_init(vpu_init);\r
1244 module_exit(vpu_exit);\r
1245 \r
1246 int vpu_hw_reset(void)\r
1247 {\r
1248     vpu_logd("request vpu reset from application. \n");\r
1249     return 0;\r
1250 }\r
1251 \r
1252 #if 0\r
1253 static int vpu_set_clk_by_register()\r
1254 {\r
1255     __raw_writel((~(1<<25))&__raw_readl(REG_PMU_APB_PD_MM_TOP_CFG), REG_PMU_APB_PD_MM_TOP_CFG);  //0x402b_001c  (&0xfdff_ffff)\r
1256     __raw_writel((0x02000000)|__raw_readl(REG_AON_APB_APB_EB0), REG_AON_APB_APB_EB0);  //0x402e_0000  (|0x0200_0000)\r
1257 \r
1258     __raw_writel(__raw_readl(REG_AON_APB_APB_EB1) | BIT_CODEC_EB, REG_AON_APB_APB_EB1); //0x402e_0004  (|0x0000_4000)\r
1259     __raw_writel(__raw_readl(REG_CODEC_AHB_CLOCK_SEL) | 0x0333, REG_CODEC_AHB_CLOCK_SEL); //6200_0008 (|0x0333)\r
1260     __raw_writel(__raw_readl(REG_CODEC_AHB_CKG_ENABLE) | 0x03, REG_CODEC_AHB_CKG_ENABLE); //6200_0004 (|0x03)\r
1261 \r
1262     return 0;\r
1263 }\r
1264 #endif\r
1265 \r
1266 static int vpu_clk_free(vpu_drv_context_t* vpu_context)\r
1267 {\r
1268     if (vpu_context->clk_coda7_apb) {\r
1269         //clk_disable_unprepare(vpu_context->clk_coda7_apb);\r
1270         clk_disable(vpu_context->clk_coda7_apb);\r
1271     }\r
1272 \r
1273     if (vpu_context->clk_coda7_axi) {\r
1274         //clk_disable_unprepare(vpu_context->clk_coda7_axi);\r
1275         clk_disable(vpu_context->clk_coda7_axi);\r
1276     }\r
1277 \r
1278     if (vpu_context->clk_coda7_cc) {\r
1279         //clk_disable_unprepare(vpu_context->clk_coda7_cc);\r
1280         clk_disable(vpu_context->clk_coda7_cc);\r
1281     }\r
1282 \r
1283     if (vpu_context->clk_coda7_apb) {\r
1284         clk_unprepare(vpu_context->clk_coda7_apb);\r
1285     }\r
1286 \r
1287     if (vpu_context->clk_coda7_axi) {\r
1288         clk_unprepare(vpu_context->clk_coda7_axi);\r
1289     }\r
1290 \r
1291     if (vpu_context->clk_coda7_cc) {\r
1292         clk_unprepare(vpu_context->clk_coda7_cc);\r
1293     }\r
1294 \r
1295     if (vpu_context->clk_mm_i) {\r
1296         clk_disable_unprepare(vpu_context->clk_mm_i);\r
1297     }\r
1298 \r
1299     return 0;\r
1300 }\r
1301 \r
1302 static int vpu_set_parent_for_coda7l_clk()\r
1303 {\r
1304     struct clk *clk_parent;\r
1305     char *name_parent;\r
1306     int ret =0;\r
1307 \r
1308     name_parent = vpu_get_clk_src_name(3, clock_coda7l_axi_map);\r
1309     clk_parent = clk_get(NULL, name_parent);\r
1310     printk(KERN_ERR "clock[%s]: get parent in probe[%s] by clk_get()!\n", "clk_coda7_axi", name_parent);\r
1311     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1312         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_axi", name_parent);\r
1313         ret = -EINVAL;\r
1314     } else {\r
1315         s_vpu_drv_context.clk_parent_axi= clk_parent;\r
1316     }\r
1317 \r
1318     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_axi, s_vpu_drv_context.clk_parent_axi);\r
1319     if (ret) {\r
1320         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_axi");\r
1321         ret = -EINVAL;\r
1322     }\r
1323 \r
1324     name_parent = vpu_get_clk_src_name(s_vpu_drv_context.freq_div, clock_coda7l_axi_map);\r
1325     clk_parent = clk_get(NULL, name_parent);\r
1326     printk(KERN_ERR "clock[%s]: get parent in probe[%s] by clk_get()!\n", "clk_coda7_axi", name_parent);\r
1327     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1328         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_axi", name_parent);\r
1329         ret = -EINVAL;\r
1330     } else {\r
1331         s_vpu_drv_context.clk_parent_axi= clk_parent;\r
1332     }\r
1333 \r
1334     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_axi, s_vpu_drv_context.clk_parent_axi);\r
1335     if (ret) {\r
1336         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_axi");\r
1337         ret = -EINVAL;\r
1338     }\r
1339 \r
1340     printk(KERN_ERR "vpu parent clock name %s, freq: %dHz\n", name_parent, (int)clk_get_rate(s_vpu_drv_context.clk_coda7_axi));\r
1341 \r
1342     name_parent = vpu_get_clk_src_name(3, clock_coda7l_cc_map);\r
1343     clk_parent = clk_get(NULL, name_parent);\r
1344     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1345         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_cc", name_parent);\r
1346         ret = -EINVAL;\r
1347     } else {\r
1348         s_vpu_drv_context.clk_parent_cc= clk_parent;\r
1349     }\r
1350 \r
1351     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_cc, s_vpu_drv_context.clk_parent_cc);\r
1352     if (ret) {\r
1353         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_cc");\r
1354         ret = -EINVAL;\r
1355     }\r
1356 \r
1357     name_parent = vpu_get_clk_src_name(s_vpu_drv_context.freq_div, clock_coda7l_cc_map);\r
1358     clk_parent = clk_get(NULL, name_parent);\r
1359     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1360         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_cc", name_parent);\r
1361         ret = -EINVAL;\r
1362     } else {\r
1363         s_vpu_drv_context.clk_parent_cc= clk_parent;\r
1364     }\r
1365 \r
1366     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_cc, s_vpu_drv_context.clk_parent_cc);\r
1367     if (ret) {\r
1368         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_cc");\r
1369         ret = -EINVAL;\r
1370     }\r
1371 \r
1372     printk(KERN_ERR "vpu parent clock name %s, freq: %dHz\n", name_parent, (int)clk_get_rate(s_vpu_drv_context.clk_coda7_cc));\r
1373 \r
1374     name_parent = vpu_get_clk_src_name(3, clock_coda7l_apb_map);\r
1375     clk_parent = clk_get(NULL, name_parent);\r
1376     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1377         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_apb", name_parent);\r
1378         ret = -EINVAL;\r
1379     } else {\r
1380         s_vpu_drv_context.clk_parent_apb= clk_parent;\r
1381     }\r
1382 \r
1383     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_apb, s_vpu_drv_context.clk_parent_apb);\r
1384     if (ret) {\r
1385         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_apb");\r
1386         ret = -EINVAL;\r
1387     }\r
1388 \r
1389     name_parent = vpu_get_clk_src_name(s_vpu_drv_context.freq_div, clock_coda7l_apb_map);\r
1390     clk_parent = clk_get(NULL, name_parent);\r
1391     if ((!clk_parent )|| IS_ERR(clk_parent) ) {\r
1392         printk(KERN_ERR "clock[%s]: failed to get parent in probe[%s] by clk_get()!\n", "clk_coda7_apb", name_parent);\r
1393         ret = -EINVAL;\r
1394     } else {\r
1395         s_vpu_drv_context.clk_parent_apb= clk_parent;\r
1396     }\r
1397 \r
1398     ret = clk_set_parent(s_vpu_drv_context.clk_coda7_apb, s_vpu_drv_context.clk_parent_apb);\r
1399     if (ret) {\r
1400         printk(KERN_ERR "clock[%s]: clk_set_parent() failed in probe!", "clk_coda7_apb");\r
1401         ret = -EINVAL;\r
1402     }\r
1403 \r
1404     printk(KERN_ERR "vpu parent clock name %s, freq: %dHz\n", name_parent, (int)clk_get_rate(s_vpu_drv_context.clk_coda7_apb));\r
1405 \r
1406     return ret;\r
1407 }\r
1408 static int vpu_set_mm_clk(void)\r
1409 {\r
1410     int ret =0;\r
1411     struct clk *clk_mm_i;\r
1412     struct clk *clk_coda7_axi;\r
1413     struct clk *clk_coda7_cc;\r
1414     struct clk *clk_coda7_apb;\r
1415 \r
1416 #if defined(CONFIG_ARCH_SCX35)\r
1417 \r
1418 //Config for clk_mm_i\r
1419 #ifdef CONFIG_OF\r
1420     clk_mm_i = of_clk_get_by_name(s_vpu_drv_context.dev_np, "clk_mm_i");\r
1421 #else\r
1422     clk_mm_i = clk_get(NULL, "clk_mm_i");\r
1423 #endif\r
1424 \r
1425     if (IS_ERR(clk_mm_i) || (!clk_mm_i)) {\r
1426         printk(KERN_ERR "###: Failed : Can't get clock [%s}!\n",\r
1427                "clk_mm_i");\r
1428         printk(KERN_ERR "###: clk_mm_i =  %p\n", clk_mm_i);\r
1429         ret = -EINVAL;\r
1430         goto errout;\r
1431     } else {\r
1432         s_vpu_drv_context.clk_mm_i= clk_mm_i;\r
1433     }\r
1434 \r
1435     ret = clk_prepare_enable(s_vpu_drv_context.clk_mm_i);\r
1436     if (ret) {\r
1437         printk(KERN_ERR "###:s_vpu_drv_context.clk_mm_i: clk_enable() failed!\n");\r
1438         return ret;\r
1439     }\r
1440 #endif\r
1441 \r
1442 //Config for clk_coda7_axi\r
1443 #ifdef CONFIG_OF\r
1444     clk_coda7_axi = of_clk_get_by_name(s_vpu_drv_context.dev_np, "clk_coda7_axi");\r
1445 #else\r
1446     clk_coda7_axi = clk_get(NULL, "clk_coda7_axi");\r
1447 #endif\r
1448 \r
1449     if (IS_ERR(clk_coda7_axi) || (!clk_coda7_axi)) {\r
1450         printk(KERN_ERR "###: Failed : Can't get clock [%s}!\n", "clk_coda7_axi");\r
1451         printk(KERN_ERR "###: clk_coda7_axi =  %p\n", clk_coda7_axi);\r
1452         ret = -EINVAL;\r
1453         goto errout;\r
1454     } else {\r
1455         s_vpu_drv_context.clk_coda7_axi = clk_coda7_axi;\r
1456     }\r
1457 \r
1458     ret = clk_prepare_enable(s_vpu_drv_context.clk_coda7_axi);\r
1459     if (ret) {\r
1460         printk(KERN_ERR "###: clk_coda7_axi: clk_enable() failed!\n");\r
1461         return ret;\r
1462     }\r
1463 \r
1464 //Config for clk_coda7_cc\r
1465 #ifdef CONFIG_OF\r
1466     clk_coda7_cc = of_clk_get_by_name(s_vpu_drv_context.dev_np, "clk_coda7_cc");\r
1467 #else\r
1468     clk_coda7_cc = clk_get(NULL, "clk_coda7_cc");\r
1469 #endif\r
1470 \r
1471     if (IS_ERR(clk_coda7_cc) || (!clk_coda7_cc)) {\r
1472         printk(KERN_ERR "###: Failed : Can't get clock [%s}!\n", "clk_coda7_cc");\r
1473         printk(KERN_ERR "###: clk_coda7_cc =  %p\n", clk_coda7_cc);\r
1474         ret = -EINVAL;\r
1475         goto errout;\r
1476     } else {\r
1477         s_vpu_drv_context.clk_coda7_cc = clk_coda7_cc;\r
1478     }\r
1479 \r
1480     ret = clk_prepare_enable(s_vpu_drv_context.clk_coda7_cc);\r
1481     if (ret) {\r
1482         printk(KERN_ERR "###: clk_coda7_cc: clk_enable() failed!\n");\r
1483         return ret;\r
1484     }\r
1485 \r
1486 //Config for clk_coda7_apb\r
1487 #ifdef CONFIG_OF\r
1488     clk_coda7_apb = of_clk_get_by_name(s_vpu_drv_context.dev_np, "clk_coda7_apb");\r
1489 #else\r
1490     clk_coda7_apb = clk_get(NULL, "clk_coda7_apb");\r
1491 #endif\r
1492 \r
1493     if (IS_ERR(clk_coda7_apb) || (!clk_coda7_apb)) {\r
1494         printk(KERN_ERR "###: Failed : Can't get clock [%s}!\n", "clk_coda7_cc");\r
1495         printk(KERN_ERR "###: clk_coda7_cc =  %p\n", clk_coda7_apb);\r
1496         ret = -EINVAL;\r
1497         goto errout;\r
1498     } else {\r
1499         s_vpu_drv_context.clk_coda7_apb = clk_coda7_apb;\r
1500     }\r
1501 \r
1502     ret = clk_prepare_enable(s_vpu_drv_context.clk_coda7_apb);\r
1503     if (ret) {\r
1504         printk(KERN_ERR "###: clk_coda7_apb: clk_enable() failed!\n");\r
1505         return ret;\r
1506     }\r
1507 \r
1508     ret = vpu_set_parent_for_coda7l_clk();\r
1509     if(ret) {\r
1510         printk(KERN_ERR "###:vpu set parent failed!\n");\r
1511         return ret;\r
1512     }\r
1513 \r
1514     return 0;\r
1515 \r
1516 errout:\r
1517 \r
1518     vpu_clk_free(&s_vpu_drv_context);\r
1519 \r
1520     return ret;\r
1521 }\r
1522 \r
1523 struct clk *vpu_clk_get(struct device *dev)\r
1524 {\r
1525     return clk_get(dev, VPU_CLK_NAME);\r
1526 }\r
1527 void vpu_clk_put(struct clk *clk)\r
1528 {\r
1529     if (!(clk == NULL || IS_ERR(clk)))\r
1530         clk_put(clk);\r
1531 }\r
1532 int vpu_clk_enable(struct clk *clk)\r
1533 {\r
1534 \r
1535 #if 0\r
1536     if (!(clk == NULL || IS_ERR(clk))) {\r
1537         /* the bellow is for C&M EVB.*/\r
1538         {\r
1539             struct clk *s_vpuext_clk = NULL;\r
1540             s_vpuext_clk = clk_get(NULL, "vcore");\r
1541             if (s_vpuext_clk)\r
1542             {\r
1543                 vpu_logi("[VPUDRV] vcore clk=%p\n", s_vpuext_clk);\r
1544                 clk_enable(s_vpuext_clk);\r
1545             }\r
1546 \r
1547             vpu_logi("[VPUDRV] vbus clk=%p\n", s_vpuext_clk);\r
1548             if (s_vpuext_clk)\r
1549             {\r
1550                 s_vpuext_clk = clk_get(NULL, "vbus");\r
1551                 clk_enable(s_vpuext_clk);\r
1552             }\r
1553         }\r
1554 \r
1555         /* for C&M EVB. */\r
1556         return clk_enable(clk);\r
1557     }\r
1558 #endif\r
1559 \r
1560     return 0;\r
1561 }\r
1562 \r
1563 void vpu_clk_disable(struct clk *clk)\r
1564 {\r
1565 #if 0\r
1566     if (!(clk == NULL || IS_ERR(clk))) {\r
1567         vpu_logd("[VPUDRV] vpu_clk_disable\n");\r
1568         clk_disable(clk);\r
1569     }\r
1570 #endif\r
1571 }\r
1572 \r
1573 \r