4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * DSP/BIOS Bridge driver interface.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
19 /* ----------------------------------- Host OS */
23 #include <dspbridge/host_os.h>
24 #include <linux/types.h>
25 #include <linux/platform_device.h>
29 #include <linux/module.h>
32 #include <linux/device.h>
33 #include <linux/init.h>
34 #include <linux/moduleparam.h>
35 #include <linux/cdev.h>
37 /* ----------------------------------- DSP/BIOS Bridge */
38 #include <dspbridge/dbdefs.h>
40 /* ----------------------------------- Trace & Debug */
41 #include <dspbridge/dbc.h>
43 /* ----------------------------------- OS Adaptation Layer */
44 #include <dspbridge/clk.h>
45 #include <dspbridge/sync.h>
47 /* ----------------------------------- Platform Manager */
48 #include <dspbridge/dspapi-ioctl.h>
49 #include <dspbridge/dspapi.h>
50 #include <dspbridge/dspdrv.h>
52 /* ----------------------------------- Resource Manager */
53 #include <dspbridge/pwr.h>
55 /* ----------------------------------- This */
56 #include <drv_interface.h>
58 #include <dspbridge/resourcecleanup.h>
59 #include <dspbridge/chnl.h>
60 #include <dspbridge/proc.h>
61 #include <dspbridge/dev.h>
62 #include <dspbridge/drvdefs.h>
63 #include <dspbridge/drv.h>
65 #ifdef CONFIG_TIDSPBRIDGE_DVFS
66 #include <mach-omap2/omap3-opp.h>
69 /* ----------------------------------- Globals */
70 #define DRIVER_NAME "DspBridge"
71 #define DSPBRIDGE_VERSION "0.3"
74 struct platform_device
*omap_dspbridge_dev
;
75 struct device
*bridge
;
77 /* This is a test variable used by Bridge to test different sleep states */
78 s32 dsp_test_sleepstate
;
80 static struct cdev bridge_cdev
;
82 static struct class *bridge_class
;
84 static u32 driver_context
;
85 static s32 driver_major
;
86 static char *base_img
;
88 static s32 shm_size
= 0x500000; /* 5 MB */
89 static int tc_wordswapon
; /* Default value is always false */
90 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
91 #define REC_TIMEOUT 5000 /*recovery timeout in msecs */
92 static atomic_t bridge_cref
; /* number of bridge open handles */
93 static struct workqueue_struct
*bridge_rec_queue
;
94 static struct work_struct bridge_recovery_work
;
95 static DECLARE_COMPLETION(bridge_comp
);
96 static DECLARE_COMPLETION(bridge_open_comp
);
101 struct omap34_xx_bridge_suspend_data
{
103 wait_queue_head_t suspend_wq
;
106 static struct omap34_xx_bridge_suspend_data bridge_suspend_data
;
108 static int omap34_xxbridge_suspend_lockout(struct omap34_xx_bridge_suspend_data
111 if ((s
)->suspended
) {
112 if ((f
)->f_flags
& O_NONBLOCK
)
114 wait_event_interruptible((s
)->suspend_wq
, (s
)->suspended
== 0);
120 module_param(dsp_debug
, int, 0);
121 MODULE_PARM_DESC(dsp_debug
, "Wait after loading DSP image. default = false");
123 module_param(dsp_test_sleepstate
, int, 0);
124 MODULE_PARM_DESC(dsp_test_sleepstate
, "DSP Sleep state = 0");
126 module_param(base_img
, charp
, 0);
127 MODULE_PARM_DESC(base_img
, "DSP base image, default = NULL");
129 module_param(shm_size
, int, 0);
130 MODULE_PARM_DESC(shm_size
, "shm size, default = 4 MB, minimum = 64 KB");
132 module_param(tc_wordswapon
, int, 0);
133 MODULE_PARM_DESC(tc_wordswapon
, "TC Word Swap Option. default = 0");
135 MODULE_AUTHOR("Texas Instruments");
136 MODULE_LICENSE("GPL");
137 MODULE_VERSION(DSPBRIDGE_VERSION
);
139 static char *driver_name
= DRIVER_NAME
;
141 static const struct file_operations bridge_fops
= {
143 .release
= bridge_release
,
144 .unlocked_ioctl
= bridge_ioctl
,
146 .llseek
= noop_llseek
,
150 static u32 time_out
= 1000;
151 #ifdef CONFIG_TIDSPBRIDGE_DVFS
152 s32 dsp_max_opps
= VDD1_OPP5
;
155 /* Maximum Opps that can be requested by IVA */
157 #ifdef CONFIG_TIDSPBRIDGE_DVFS
158 const struct omap_opp vdd1_rate_table_bridge
[] = {
161 {S125M
, VDD1_OPP1
, 0},
163 {S250M
, VDD1_OPP2
, 0},
165 {S500M
, VDD1_OPP3
, 0},
167 {S550M
, VDD1_OPP4
, 0},
169 {S600M
, VDD1_OPP5
, 0},
174 struct omap_dsp_platform_data
*omap_dspbridge_pdata
;
176 u32 vdd1_dsp_freq
[6][4] = {
179 {0, 90000, 0, 86000},
181 {0, 180000, 80000, 170000},
183 {0, 360000, 160000, 340000},
185 {0, 396000, 325000, 376000},
187 {0, 430000, 355000, 430000},
190 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
191 static void bridge_recover(struct work_struct
*work
)
193 struct dev_object
*dev
;
194 struct cfg_devnode
*dev_node
;
195 if (atomic_read(&bridge_cref
)) {
196 INIT_COMPLETION(bridge_comp
);
197 while (!wait_for_completion_timeout(&bridge_comp
,
198 msecs_to_jiffies(REC_TIMEOUT
)))
199 pr_info("%s:%d handle(s) still opened\n",
200 __func__
, atomic_read(&bridge_cref
));
202 dev
= dev_get_first();
203 dev_get_dev_node(dev
, &dev_node
);
204 if (!dev_node
|| proc_auto_start(dev_node
, dev
))
205 pr_err("DSP could not be restarted\n");
207 complete_all(&bridge_open_comp
);
210 void bridge_recover_schedule(void)
212 INIT_COMPLETION(bridge_open_comp
);
214 queue_work(bridge_rec_queue
, &bridge_recovery_work
);
217 #ifdef CONFIG_TIDSPBRIDGE_DVFS
218 static int dspbridge_scale_notification(struct notifier_block
*op
,
219 unsigned long val
, void *ptr
)
221 struct omap_dsp_platform_data
*pdata
=
222 omap_dspbridge_dev
->dev
.platform_data
;
224 if (CPUFREQ_POSTCHANGE
== val
&& pdata
->dsp_get_opp
)
225 pwr_pm_post_scale(PRCM_VDD1
, pdata
->dsp_get_opp());
230 static struct notifier_block iva_clk_notifier
= {
231 .notifier_call
= dspbridge_scale_notification
,
237 * omap3_bridge_startup() - perform low lever initializations
238 * @pdev: pointer to platform device
240 * Initializes recovery, PM and DVFS required data, before calling
241 * clk and memory init routines.
243 static int omap3_bridge_startup(struct platform_device
*pdev
)
245 struct omap_dsp_platform_data
*pdata
= pdev
->dev
.platform_data
;
246 struct drv_data
*drv_datap
= NULL
;
247 u32 phys_membase
, phys_memsize
;
250 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
251 bridge_rec_queue
= create_workqueue("bridge_rec_queue");
252 INIT_WORK(&bridge_recovery_work
, bridge_recover
);
253 INIT_COMPLETION(bridge_comp
);
257 /* Initialize the wait queue */
258 bridge_suspend_data
.suspended
= 0;
259 init_waitqueue_head(&bridge_suspend_data
.suspend_wq
);
261 #ifdef CONFIG_TIDSPBRIDGE_DVFS
262 for (i
= 0; i
< 6; i
++)
263 pdata
->mpu_speed
[i
] = vdd1_rate_table_bridge
[i
].rate
;
265 err
= cpufreq_register_notifier(&iva_clk_notifier
,
266 CPUFREQ_TRANSITION_NOTIFIER
);
268 pr_err("%s: clk_notifier_register failed for iva2_ck\n",
275 drv_datap
= kzalloc(sizeof(struct drv_data
), GFP_KERNEL
);
281 drv_datap
->shm_size
= shm_size
;
282 drv_datap
->tc_wordswapon
= tc_wordswapon
;
285 drv_datap
->base_img
= kmalloc(strlen(base_img
) + 1, GFP_KERNEL
);
286 if (!drv_datap
->base_img
) {
290 strncpy(drv_datap
->base_img
, base_img
, strlen(base_img
) + 1);
293 dev_set_drvdata(bridge
, drv_datap
);
295 if (shm_size
< 0x10000) { /* 64 KB */
297 pr_err("%s: shm size must be at least 64 KB\n", __func__
);
300 dev_dbg(bridge
, "%s: requested shm_size = 0x%x\n", __func__
, shm_size
);
302 phys_membase
= pdata
->phys_mempool_base
;
303 phys_memsize
= pdata
->phys_mempool_size
;
304 if (phys_membase
> 0 && phys_memsize
> 0)
305 mem_ext_phys_pool_init(phys_membase
, phys_memsize
);
308 dev_dbg(bridge
, "%s: TC Word Swap is enabled\n", __func__
);
310 driver_context
= dsp_init(&err
);
312 pr_err("DSP Bridge driver initialization failed\n");
319 mem_ext_phys_pool_release();
321 kfree(drv_datap
->base_img
);
325 #ifdef CONFIG_TIDSPBRIDGE_DVFS
326 cpufreq_unregister_notifier(&iva_clk_notifier
,
327 CPUFREQ_TRANSITION_NOTIFIER
);
334 static int __devinit
omap34_xx_bridge_probe(struct platform_device
*pdev
)
338 #ifdef CONFIG_TIDSPBRIDGE_DVFS
342 omap_dspbridge_dev
= pdev
;
344 /* Global bridge device */
345 bridge
= &omap_dspbridge_dev
->dev
;
347 /* Bridge low level initializations */
348 err
= omap3_bridge_startup(pdev
);
352 /* use 2.6 device model */
353 err
= alloc_chrdev_region(&dev
, 0, 1, driver_name
);
355 pr_err("%s: Can't get major %d\n", __func__
, driver_major
);
359 cdev_init(&bridge_cdev
, &bridge_fops
);
360 bridge_cdev
.owner
= THIS_MODULE
;
362 err
= cdev_add(&bridge_cdev
, dev
, 1);
364 pr_err("%s: Failed to add bridge device\n", __func__
);
369 bridge_class
= class_create(THIS_MODULE
, "ti_bridge");
370 if (IS_ERR(bridge_class
)) {
371 pr_err("%s: Error creating bridge class\n", __func__
);
375 driver_major
= MAJOR(dev
);
376 device_create(bridge_class
, NULL
, MKDEV(driver_major
, 0),
378 pr_info("DSP Bridge driver loaded\n");
383 cdev_del(&bridge_cdev
);
385 unregister_chrdev_region(dev
, 1);
390 static int __devexit
omap34_xx_bridge_remove(struct platform_device
*pdev
)
395 struct drv_data
*drv_datap
= dev_get_drvdata(bridge
);
397 /* Retrieve the Object handle from the driver data */
398 if (!drv_datap
|| !drv_datap
->drv_object
) {
400 pr_err("%s: Failed to retrieve the object handle\n", __func__
);
404 #ifdef CONFIG_TIDSPBRIDGE_DVFS
405 if (cpufreq_unregister_notifier(&iva_clk_notifier
,
406 CPUFREQ_TRANSITION_NOTIFIER
))
407 pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n",
409 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
411 if (driver_context
) {
412 /* Put the DSP in reset state */
413 ret
= dsp_deinit(driver_context
);
415 DBC_ASSERT(ret
== true);
419 mem_ext_phys_pool_release();
423 devno
= MKDEV(driver_major
, 0);
424 cdev_del(&bridge_cdev
);
425 unregister_chrdev_region(devno
, 1);
427 /* remove the device from sysfs */
428 device_destroy(bridge_class
, MKDEV(driver_major
, 0));
429 class_destroy(bridge_class
);
436 static int BRIDGE_SUSPEND(struct platform_device
*pdev
, pm_message_t state
)
439 u32 command
= PWR_EMERGENCYDEEPSLEEP
;
441 status
= pwr_sleep_dsp(command
, time_out
);
445 bridge_suspend_data
.suspended
= 1;
449 static int BRIDGE_RESUME(struct platform_device
*pdev
)
453 status
= pwr_wake_dsp(time_out
);
457 bridge_suspend_data
.suspended
= 0;
458 wake_up(&bridge_suspend_data
.suspend_wq
);
462 #define BRIDGE_SUSPEND NULL
463 #define BRIDGE_RESUME NULL
466 static struct platform_driver bridge_driver
= {
470 .probe
= omap34_xx_bridge_probe
,
471 .remove
= __devexit_p(omap34_xx_bridge_remove
),
472 .suspend
= BRIDGE_SUSPEND
,
473 .resume
= BRIDGE_RESUME
,
476 static int __init
bridge_init(void)
478 return platform_driver_register(&bridge_driver
);
481 static void __exit
bridge_exit(void)
483 platform_driver_unregister(&bridge_driver
);
487 * This function is called when an application opens handle to the
490 static int bridge_open(struct inode
*ip
, struct file
*filp
)
493 struct process_context
*pr_ctxt
= NULL
;
496 * Allocate a new process context and insert it into global
497 * process context list.
500 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
502 if (filp
->f_flags
& O_NONBLOCK
||
503 wait_for_completion_interruptible(&bridge_open_comp
))
507 pr_ctxt
= kzalloc(sizeof(struct process_context
), GFP_KERNEL
);
509 pr_ctxt
->res_state
= PROC_RES_ALLOCATED
;
510 spin_lock_init(&pr_ctxt
->dmm_map_lock
);
511 INIT_LIST_HEAD(&pr_ctxt
->dmm_map_list
);
512 spin_lock_init(&pr_ctxt
->dmm_rsv_lock
);
513 INIT_LIST_HEAD(&pr_ctxt
->dmm_rsv_list
);
515 pr_ctxt
->node_id
= kzalloc(sizeof(struct idr
), GFP_KERNEL
);
516 if (pr_ctxt
->node_id
) {
517 idr_init(pr_ctxt
->node_id
);
523 pr_ctxt
->stream_id
= kzalloc(sizeof(struct idr
), GFP_KERNEL
);
524 if (pr_ctxt
->stream_id
)
525 idr_init(pr_ctxt
->stream_id
);
532 filp
->private_data
= pr_ctxt
;
533 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
535 atomic_inc(&bridge_cref
);
541 * This function is called when an application closes handle to the bridge
544 static int bridge_release(struct inode
*ip
, struct file
*filp
)
547 struct process_context
*pr_ctxt
;
549 if (!filp
->private_data
) {
554 pr_ctxt
= filp
->private_data
;
555 flush_signals(current
);
556 drv_remove_all_resources(pr_ctxt
);
557 proc_detach(pr_ctxt
);
560 filp
->private_data
= NULL
;
563 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
564 if (!atomic_dec_return(&bridge_cref
))
565 complete(&bridge_comp
);
570 /* This function provides IO interface to the bridge driver. */
571 static long bridge_ioctl(struct file
*filp
, unsigned int code
,
576 union trapped_args buf_in
;
578 DBC_REQUIRE(filp
!= NULL
);
579 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
586 status
= omap34_xxbridge_suspend_lockout(&bridge_suspend_data
, filp
);
591 if (!filp
->private_data
) {
596 status
= copy_from_user(&buf_in
, (union trapped_args
*)args
,
597 sizeof(union trapped_args
));
600 status
= api_call_dev_ioctl(code
, &buf_in
, &retval
,
606 dev_dbg(bridge
, "%s: IOCTL Failed, code: 0x%x "
607 "status 0x%x\n", __func__
, code
, status
);
617 /* This function maps kernel space memory to user space memory. */
618 static int bridge_mmap(struct file
*filp
, struct vm_area_struct
*vma
)
620 u32 offset
= vma
->vm_pgoff
<< PAGE_SHIFT
;
623 DBC_ASSERT(vma
->vm_start
< vma
->vm_end
);
625 vma
->vm_flags
|= VM_RESERVED
| VM_IO
;
626 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
628 dev_dbg(bridge
, "%s: vm filp %p offset %x start %lx end %lx page_prot "
629 "%lx flags %lx\n", __func__
, filp
, offset
,
630 vma
->vm_start
, vma
->vm_end
, vma
->vm_page_prot
, vma
->vm_flags
);
632 status
= remap_pfn_range(vma
, vma
->vm_start
, vma
->vm_pgoff
,
633 vma
->vm_end
- vma
->vm_start
,
641 /* To remove all process resources before removing the process from the
642 * process context list */
643 int drv_remove_all_resources(void *process_ctxt
)
646 struct process_context
*ctxt
= (struct process_context
*)process_ctxt
;
647 drv_remove_all_strm_res_elements(ctxt
);
648 drv_remove_all_node_res_elements(ctxt
);
649 drv_remove_all_dmm_res_elements(ctxt
);
650 ctxt
->res_state
= PROC_RES_FREED
;
654 /* Bridge driver initialization and de-initialization functions */
655 module_init(bridge_init
);
656 module_exit(bridge_exit
);