Merge branch 'rmobile-fixes-for-linus' of git://github.com/pmundt/linux-sh
[pandora-kernel.git] / drivers / staging / tidspbridge / rmgr / drv_interface.c
1 /*
2  * drv_interface.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * DSP/BIOS Bridge driver interface.
7  *
8  * Copyright (C) 2005-2006 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18
19 /*  ----------------------------------- Host OS */
20
21 #include <plat/dsp.h>
22
23 #include <dspbridge/host_os.h>
24 #include <linux/types.h>
25 #include <linux/platform_device.h>
26 #include <linux/pm.h>
27 #include <linux/module.h>
28 #include <linux/device.h>
29 #include <linux/init.h>
30 #include <linux/moduleparam.h>
31 #include <linux/cdev.h>
32
33 /*  ----------------------------------- DSP/BIOS Bridge */
34 #include <dspbridge/dbdefs.h>
35
36 /*  ----------------------------------- Trace & Debug */
37 #include <dspbridge/dbc.h>
38
39 /*  ----------------------------------- OS Adaptation Layer */
40 #include <dspbridge/clk.h>
41 #include <dspbridge/sync.h>
42
43 /*  ----------------------------------- Platform Manager */
44 #include <dspbridge/dspapi-ioctl.h>
45 #include <dspbridge/dspapi.h>
46 #include <dspbridge/dspdrv.h>
47
48 /*  ----------------------------------- Resource Manager */
49 #include <dspbridge/pwr.h>
50
51 /*  ----------------------------------- This */
52 #include <drv_interface.h>
53
54 #include <dspbridge/resourcecleanup.h>
55 #include <dspbridge/chnl.h>
56 #include <dspbridge/proc.h>
57 #include <dspbridge/dev.h>
58 #include <dspbridge/drv.h>
59
60 #ifdef CONFIG_TIDSPBRIDGE_DVFS
61 #include <mach-omap2/omap3-opp.h>
62 #endif
63
64 /*  ----------------------------------- Globals */
65 #define DRIVER_NAME  "DspBridge"
66 #define DSPBRIDGE_VERSION       "0.3"
67 s32 dsp_debug;
68
69 struct platform_device *omap_dspbridge_dev;
70 struct device *bridge;
71
72 /* This is a test variable used by Bridge to test different sleep states */
73 s32 dsp_test_sleepstate;
74
75 static struct cdev bridge_cdev;
76
77 static struct class *bridge_class;
78
79 static u32 driver_context;
80 static s32 driver_major;
81 static char *base_img;
82 char *iva_img;
83 static s32 shm_size = 0x500000; /* 5 MB */
84 static int tc_wordswapon;       /* Default value is always false */
85 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
86 #define REC_TIMEOUT 5000        /*recovery timeout in msecs */
87 static atomic_t bridge_cref;    /* number of bridge open handles */
88 static struct workqueue_struct *bridge_rec_queue;
89 static struct work_struct bridge_recovery_work;
90 static DECLARE_COMPLETION(bridge_comp);
91 static DECLARE_COMPLETION(bridge_open_comp);
92 static bool recover;
93 #endif
94
95 #ifdef CONFIG_PM
96 struct omap34_xx_bridge_suspend_data {
97         int suspended;
98         wait_queue_head_t suspend_wq;
99 };
100
101 static struct omap34_xx_bridge_suspend_data bridge_suspend_data;
102
103 static int omap34_xxbridge_suspend_lockout(struct omap34_xx_bridge_suspend_data
104                                            *s, struct file *f)
105 {
106         if ((s)->suspended) {
107                 if ((f)->f_flags & O_NONBLOCK)
108                         return -EPERM;
109                 wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0);
110         }
111         return 0;
112 }
113 #endif
114
115 module_param(dsp_debug, int, 0);
116 MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false");
117
118 module_param(dsp_test_sleepstate, int, 0);
119 MODULE_PARM_DESC(dsp_test_sleepstate, "DSP Sleep state = 0");
120
121 module_param(base_img, charp, 0);
122 MODULE_PARM_DESC(base_img, "DSP base image, default = NULL");
123
124 module_param(shm_size, int, 0);
125 MODULE_PARM_DESC(shm_size, "shm size, default = 4 MB, minimum = 64 KB");
126
127 module_param(tc_wordswapon, int, 0);
128 MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0");
129
130 MODULE_AUTHOR("Texas Instruments");
131 MODULE_LICENSE("GPL");
132 MODULE_VERSION(DSPBRIDGE_VERSION);
133
134 static char *driver_name = DRIVER_NAME;
135
136 static const struct file_operations bridge_fops = {
137         .open = bridge_open,
138         .release = bridge_release,
139         .unlocked_ioctl = bridge_ioctl,
140         .mmap = bridge_mmap,
141         .llseek = noop_llseek,
142 };
143
144 #ifdef CONFIG_PM
145 static u32 time_out = 1000;
146 #ifdef CONFIG_TIDSPBRIDGE_DVFS
147 s32 dsp_max_opps = VDD1_OPP5;
148 #endif
149
150 /* Maximum Opps that can be requested by IVA */
151 /*vdd1 rate table */
152 #ifdef CONFIG_TIDSPBRIDGE_DVFS
153 const struct omap_opp vdd1_rate_table_bridge[] = {
154         {0, 0, 0},
155         /*OPP1 */
156         {S125M, VDD1_OPP1, 0},
157         /*OPP2 */
158         {S250M, VDD1_OPP2, 0},
159         /*OPP3 */
160         {S500M, VDD1_OPP3, 0},
161         /*OPP4 */
162         {S550M, VDD1_OPP4, 0},
163         /*OPP5 */
164         {S600M, VDD1_OPP5, 0},
165 };
166 #endif
167 #endif
168
169 struct omap_dsp_platform_data *omap_dspbridge_pdata;
170
171 u32 vdd1_dsp_freq[6][4] = {
172         {0, 0, 0, 0},
173         /*OPP1 */
174         {0, 90000, 0, 86000},
175         /*OPP2 */
176         {0, 180000, 80000, 170000},
177         /*OPP3 */
178         {0, 360000, 160000, 340000},
179         /*OPP4 */
180         {0, 396000, 325000, 376000},
181         /*OPP5 */
182         {0, 430000, 355000, 430000},
183 };
184
185 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
186 static void bridge_recover(struct work_struct *work)
187 {
188         struct dev_object *dev;
189         struct cfg_devnode *dev_node;
190         if (atomic_read(&bridge_cref)) {
191                 INIT_COMPLETION(bridge_comp);
192                 while (!wait_for_completion_timeout(&bridge_comp,
193                                                 msecs_to_jiffies(REC_TIMEOUT)))
194                         pr_info("%s:%d handle(s) still opened\n",
195                                         __func__, atomic_read(&bridge_cref));
196         }
197         dev = dev_get_first();
198         dev_get_dev_node(dev, &dev_node);
199         if (!dev_node || proc_auto_start(dev_node, dev))
200                 pr_err("DSP could not be restarted\n");
201         recover = false;
202         complete_all(&bridge_open_comp);
203 }
204
205 void bridge_recover_schedule(void)
206 {
207         INIT_COMPLETION(bridge_open_comp);
208         recover = true;
209         queue_work(bridge_rec_queue, &bridge_recovery_work);
210 }
211 #endif
212 #ifdef CONFIG_TIDSPBRIDGE_DVFS
213 static int dspbridge_scale_notification(struct notifier_block *op,
214                 unsigned long val, void *ptr)
215 {
216         struct omap_dsp_platform_data *pdata =
217                 omap_dspbridge_dev->dev.platform_data;
218
219         if (CPUFREQ_POSTCHANGE == val && pdata->dsp_get_opp)
220                 pwr_pm_post_scale(PRCM_VDD1, pdata->dsp_get_opp());
221
222         return 0;
223 }
224
225 static struct notifier_block iva_clk_notifier = {
226         .notifier_call = dspbridge_scale_notification,
227         NULL,
228 };
229 #endif
230
231 /**
232  * omap3_bridge_startup() - perform low lever initializations
233  * @pdev:      pointer to platform device
234  *
235  * Initializes recovery, PM and DVFS required data, before calling
236  * clk and memory init routines.
237  */
238 static int omap3_bridge_startup(struct platform_device *pdev)
239 {
240         struct omap_dsp_platform_data *pdata = pdev->dev.platform_data;
241         struct drv_data *drv_datap = NULL;
242         u32 phys_membase, phys_memsize;
243         int err;
244
245 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
246         bridge_rec_queue = create_workqueue("bridge_rec_queue");
247         INIT_WORK(&bridge_recovery_work, bridge_recover);
248         INIT_COMPLETION(bridge_comp);
249 #endif
250
251 #ifdef CONFIG_PM
252         /* Initialize the wait queue */
253         bridge_suspend_data.suspended = 0;
254         init_waitqueue_head(&bridge_suspend_data.suspend_wq);
255
256 #ifdef CONFIG_TIDSPBRIDGE_DVFS
257         for (i = 0; i < 6; i++)
258                 pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate;
259
260         err = cpufreq_register_notifier(&iva_clk_notifier,
261                                         CPUFREQ_TRANSITION_NOTIFIER);
262         if (err)
263                 pr_err("%s: clk_notifier_register failed for iva2_ck\n",
264                                                                 __func__);
265 #endif
266 #endif
267
268         dsp_clk_init();
269
270         drv_datap = kzalloc(sizeof(struct drv_data), GFP_KERNEL);
271         if (!drv_datap) {
272                 err = -ENOMEM;
273                 goto err1;
274         }
275
276         drv_datap->shm_size = shm_size;
277         drv_datap->tc_wordswapon = tc_wordswapon;
278
279         if (base_img) {
280                 drv_datap->base_img = kmalloc(strlen(base_img) + 1, GFP_KERNEL);
281                 if (!drv_datap->base_img) {
282                         err = -ENOMEM;
283                         goto err2;
284                 }
285                 strncpy(drv_datap->base_img, base_img, strlen(base_img) + 1);
286         }
287
288         dev_set_drvdata(bridge, drv_datap);
289
290         if (shm_size < 0x10000) {       /* 64 KB */
291                 err = -EINVAL;
292                 pr_err("%s: shm size must be at least 64 KB\n", __func__);
293                 goto err3;
294         }
295         dev_dbg(bridge, "%s: requested shm_size = 0x%x\n", __func__, shm_size);
296
297         phys_membase = pdata->phys_mempool_base;
298         phys_memsize = pdata->phys_mempool_size;
299         if (phys_membase > 0 && phys_memsize > 0)
300                 mem_ext_phys_pool_init(phys_membase, phys_memsize);
301
302         if (tc_wordswapon)
303                 dev_dbg(bridge, "%s: TC Word Swap is enabled\n", __func__);
304
305         driver_context = dsp_init(&err);
306         if (err) {
307                 pr_err("DSP Bridge driver initialization failed\n");
308                 goto err4;
309         }
310
311         return 0;
312
313 err4:
314         mem_ext_phys_pool_release();
315 err3:
316         kfree(drv_datap->base_img);
317 err2:
318         kfree(drv_datap);
319 err1:
320 #ifdef CONFIG_TIDSPBRIDGE_DVFS
321         cpufreq_unregister_notifier(&iva_clk_notifier,
322                                         CPUFREQ_TRANSITION_NOTIFIER);
323 #endif
324         dsp_clk_exit();
325
326         return err;
327 }
328
329 static int __devinit omap34_xx_bridge_probe(struct platform_device *pdev)
330 {
331         int err;
332         dev_t dev = 0;
333 #ifdef CONFIG_TIDSPBRIDGE_DVFS
334         int i = 0;
335 #endif
336
337         omap_dspbridge_dev = pdev;
338
339         /* Global bridge device */
340         bridge = &omap_dspbridge_dev->dev;
341
342         /* Bridge low level initializations */
343         err = omap3_bridge_startup(pdev);
344         if (err)
345                 goto err1;
346
347         /* use 2.6 device model */
348         err = alloc_chrdev_region(&dev, 0, 1, driver_name);
349         if (err) {
350                 pr_err("%s: Can't get major %d\n", __func__, driver_major);
351                 goto err1;
352         }
353
354         cdev_init(&bridge_cdev, &bridge_fops);
355         bridge_cdev.owner = THIS_MODULE;
356
357         err = cdev_add(&bridge_cdev, dev, 1);
358         if (err) {
359                 pr_err("%s: Failed to add bridge device\n", __func__);
360                 goto err2;
361         }
362
363         /* udev support */
364         bridge_class = class_create(THIS_MODULE, "ti_bridge");
365         if (IS_ERR(bridge_class)) {
366                 pr_err("%s: Error creating bridge class\n", __func__);
367                 goto err3;
368         }
369
370         driver_major = MAJOR(dev);
371         device_create(bridge_class, NULL, MKDEV(driver_major, 0),
372                       NULL, "DspBridge");
373         pr_info("DSP Bridge driver loaded\n");
374
375         return 0;
376
377 err3:
378         cdev_del(&bridge_cdev);
379 err2:
380         unregister_chrdev_region(dev, 1);
381 err1:
382         return err;
383 }
384
385 static int __devexit omap34_xx_bridge_remove(struct platform_device *pdev)
386 {
387         dev_t devno;
388         bool ret;
389         int status = 0;
390         struct drv_data *drv_datap = dev_get_drvdata(bridge);
391
392         /* Retrieve the Object handle from the driver data */
393         if (!drv_datap || !drv_datap->drv_object) {
394                 status = -ENODATA;
395                 pr_err("%s: Failed to retrieve the object handle\n", __func__);
396                 goto func_cont;
397         }
398
399 #ifdef CONFIG_TIDSPBRIDGE_DVFS
400         if (cpufreq_unregister_notifier(&iva_clk_notifier,
401                                                 CPUFREQ_TRANSITION_NOTIFIER))
402                 pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n",
403                        __func__);
404 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
405
406         if (driver_context) {
407                 /* Put the DSP in reset state */
408                 ret = dsp_deinit(driver_context);
409                 driver_context = 0;
410                 DBC_ASSERT(ret == true);
411         }
412
413 func_cont:
414         mem_ext_phys_pool_release();
415
416         dsp_clk_exit();
417
418         devno = MKDEV(driver_major, 0);
419         cdev_del(&bridge_cdev);
420         unregister_chrdev_region(devno, 1);
421         if (bridge_class) {
422                 /* remove the device from sysfs */
423                 device_destroy(bridge_class, MKDEV(driver_major, 0));
424                 class_destroy(bridge_class);
425
426         }
427         return 0;
428 }
429
430 #ifdef CONFIG_PM
431 static int BRIDGE_SUSPEND(struct platform_device *pdev, pm_message_t state)
432 {
433         u32 status;
434         u32 command = PWR_EMERGENCYDEEPSLEEP;
435
436         status = pwr_sleep_dsp(command, time_out);
437         if (status)
438                 return -1;
439
440         bridge_suspend_data.suspended = 1;
441         return 0;
442 }
443
444 static int BRIDGE_RESUME(struct platform_device *pdev)
445 {
446         u32 status;
447
448         status = pwr_wake_dsp(time_out);
449         if (status)
450                 return -1;
451
452         bridge_suspend_data.suspended = 0;
453         wake_up(&bridge_suspend_data.suspend_wq);
454         return 0;
455 }
456 #else
457 #define BRIDGE_SUSPEND NULL
458 #define BRIDGE_RESUME NULL
459 #endif
460
461 static struct platform_driver bridge_driver = {
462         .driver = {
463                    .name = "omap-dsp",
464                    },
465         .probe = omap34_xx_bridge_probe,
466         .remove = __devexit_p(omap34_xx_bridge_remove),
467         .suspend = BRIDGE_SUSPEND,
468         .resume = BRIDGE_RESUME,
469 };
470
471 static int __init bridge_init(void)
472 {
473         return platform_driver_register(&bridge_driver);
474 }
475
476 static void __exit bridge_exit(void)
477 {
478         platform_driver_unregister(&bridge_driver);
479 }
480
481 /*
482  * This function is called when an application opens handle to the
483  * bridge driver.
484  */
485 static int bridge_open(struct inode *ip, struct file *filp)
486 {
487         int status = 0;
488         struct process_context *pr_ctxt = NULL;
489
490         /*
491          * Allocate a new process context and insert it into global
492          * process context list.
493          */
494
495 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
496         if (recover) {
497                 if (filp->f_flags & O_NONBLOCK ||
498                         wait_for_completion_interruptible(&bridge_open_comp))
499                         return -EBUSY;
500         }
501 #endif
502         pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL);
503         if (pr_ctxt) {
504                 pr_ctxt->res_state = PROC_RES_ALLOCATED;
505                 spin_lock_init(&pr_ctxt->dmm_map_lock);
506                 INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
507                 spin_lock_init(&pr_ctxt->dmm_rsv_lock);
508                 INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
509
510                 pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
511                 if (pr_ctxt->node_id) {
512                         idr_init(pr_ctxt->node_id);
513                 } else {
514                         status = -ENOMEM;
515                         goto err;
516                 }
517
518                 pr_ctxt->stream_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
519                 if (pr_ctxt->stream_id)
520                         idr_init(pr_ctxt->stream_id);
521                 else
522                         status = -ENOMEM;
523         } else {
524                 status = -ENOMEM;
525         }
526 err:
527         filp->private_data = pr_ctxt;
528 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
529         if (!status)
530                 atomic_inc(&bridge_cref);
531 #endif
532         return status;
533 }
534
535 /*
536  * This function is called when an application closes handle to the bridge
537  * driver.
538  */
539 static int bridge_release(struct inode *ip, struct file *filp)
540 {
541         int status = 0;
542         struct process_context *pr_ctxt;
543
544         if (!filp->private_data) {
545                 status = -EIO;
546                 goto err;
547         }
548
549         pr_ctxt = filp->private_data;
550         flush_signals(current);
551         drv_remove_all_resources(pr_ctxt);
552         proc_detach(pr_ctxt);
553         kfree(pr_ctxt);
554
555         filp->private_data = NULL;
556
557 err:
558 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
559         if (!atomic_dec_return(&bridge_cref))
560                 complete(&bridge_comp);
561 #endif
562         return status;
563 }
564
565 /* This function provides IO interface to the bridge driver. */
566 static long bridge_ioctl(struct file *filp, unsigned int code,
567                          unsigned long args)
568 {
569         int status;
570         u32 retval = 0;
571         union trapped_args buf_in;
572
573         DBC_REQUIRE(filp != NULL);
574 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
575         if (recover) {
576                 status = -EIO;
577                 goto err;
578         }
579 #endif
580 #ifdef CONFIG_PM
581         status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp);
582         if (status != 0)
583                 return status;
584 #endif
585
586         if (!filp->private_data) {
587                 status = -EIO;
588                 goto err;
589         }
590
591         status = copy_from_user(&buf_in, (union trapped_args *)args,
592                                 sizeof(union trapped_args));
593
594         if (!status) {
595                 status = api_call_dev_ioctl(code, &buf_in, &retval,
596                                              filp->private_data);
597
598                 if (!status) {
599                         status = retval;
600                 } else {
601                         dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x "
602                                 "status 0x%x\n", __func__, code, status);
603                         status = -1;
604                 }
605
606         }
607
608 err:
609         return status;
610 }
611
612 /* This function maps kernel space memory to user space memory. */
613 static int bridge_mmap(struct file *filp, struct vm_area_struct *vma)
614 {
615         u32 offset = vma->vm_pgoff << PAGE_SHIFT;
616         u32 status;
617
618         DBC_ASSERT(vma->vm_start < vma->vm_end);
619
620         vma->vm_flags |= VM_RESERVED | VM_IO;
621         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
622
623         dev_dbg(bridge, "%s: vm filp %p offset %x start %lx end %lx page_prot "
624                 "%lx flags %lx\n", __func__, filp, offset,
625                 vma->vm_start, vma->vm_end, vma->vm_page_prot, vma->vm_flags);
626
627         status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
628                                  vma->vm_end - vma->vm_start,
629                                  vma->vm_page_prot);
630         if (status != 0)
631                 status = -EAGAIN;
632
633         return status;
634 }
635
636 /* To remove all process resources before removing the process from the
637  * process context list */
638 int drv_remove_all_resources(void *process_ctxt)
639 {
640         int status = 0;
641         struct process_context *ctxt = (struct process_context *)process_ctxt;
642         drv_remove_all_strm_res_elements(ctxt);
643         drv_remove_all_node_res_elements(ctxt);
644         drv_remove_all_dmm_res_elements(ctxt);
645         ctxt->res_state = PROC_RES_FREED;
646         return status;
647 }
648
649 /* Bridge driver initialization and de-initialization functions */
650 module_init(bridge_init);
651 module_exit(bridge_exit);