]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/dsp_core.c
c0a06492f40a09b3aaa0cf743bc43c6614189f70
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / dsp_core.c
1 /*
2  * linux/arch/arm/mach-omap/dsp/dsp_core.c
3  *
4  * OMAP DSP driver
5  *
6  * Copyright (C) 2002-2005 Nokia Corporation
7  *
8  * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  * 2005/06/07:  DSP Gateway version 3.3
25  */
26
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
30 #include <linux/device.h>
31 #include <linux/devfs_fs_kernel.h>
32 #include <linux/sched.h>
33 #include <linux/interrupt.h>
34 #include <linux/proc_fs.h>
35 #include <asm/uaccess.h>
36 #include <asm/io.h>
37 #include <asm/signal.h>
38 #include <asm/delay.h>
39 #include <asm/irq.h>
40 #include <asm/arch/dsp.h>
41 #include "hardware_dsp.h"
42 #include "dsp.h"
43 #include "ipbuf.h"
44
45
46 MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
47 MODULE_DESCRIPTION("OMAP DSP driver module");
48 MODULE_LICENSE("GPL");
49
50 enum mbseq_check_level {
51         MBSEQ_CHECK_NONE,       /* no check */
52         MBSEQ_CHECK_VERBOSE,    /* discard the illegal command and
53                                    error report */
54         MBSEQ_CHECK_SILENT,     /* discard the illegal command */
55 };
56
57 static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE;
58
59 static int mbx1_valid;
60 static struct sync_seq *mbseq;
61 static unsigned short mbseq_expect_tmp;
62 static unsigned short *mbseq_expect = &mbseq_expect_tmp;
63
64 /*
65  * mailbox commands
66  */
67 extern void mbx1_wdsnd(struct mbcmd *mb);
68 extern void mbx1_wdreq(struct mbcmd *mb);
69 extern void mbx1_bksnd(struct mbcmd *mb);
70 extern void mbx1_bkreq(struct mbcmd *mb);
71 extern void mbx1_bkyld(struct mbcmd *mb);
72 extern void mbx1_bksndp(struct mbcmd *mb);
73 extern void mbx1_bkreqp(struct mbcmd *mb);
74 extern void mbx1_tctl(struct mbcmd *mb);
75 extern void mbx1_poll(struct mbcmd *mb);
76 #ifdef OLD_BINARY_SUPPORT
77 /* v3.3 obsolete */
78 extern void mbx1_wdt(struct mbcmd *mb);
79 #endif
80 extern void mbx1_suspend(struct mbcmd *mb);
81 static void mbx1_kfunc(struct mbcmd *mb);
82 extern void mbx1_tcfg(struct mbcmd *mb);
83 extern void mbx1_tadd(struct mbcmd *mb);
84 extern void mbx1_tdel(struct mbcmd *mb);
85 extern void mbx1_dspcfg(struct mbcmd *mb);
86 extern void mbx1_regrw(struct mbcmd *mb);
87 extern void mbx1_getvar(struct mbcmd *mb);
88 extern void mbx1_err(struct mbcmd *mb);
89 extern void mbx1_dbg(struct mbcmd *mb);
90
91 static const struct cmdinfo
92         cif_null     = { "Unknown",  CMD_L_TYPE_NULL,   NULL         },
93         cif_wdsnd    = { "WDSND",    CMD_L_TYPE_TID,    mbx1_wdsnd   },
94         cif_wdreq    = { "WDREQ",    CMD_L_TYPE_TID,    mbx1_wdreq   },
95         cif_bksnd    = { "BKSND",    CMD_L_TYPE_TID,    mbx1_bksnd   },
96         cif_bkreq    = { "BKREQ",    CMD_L_TYPE_TID,    mbx1_bkreq   },
97         cif_bkyld    = { "BKYLD",    CMD_L_TYPE_NULL,   mbx1_bkyld   },
98         cif_bksndp   = { "BKSNDP",   CMD_L_TYPE_TID,    mbx1_bksndp  },
99         cif_bkreqp   = { "BKREQP",   CMD_L_TYPE_TID,    mbx1_bkreqp  },
100         cif_tctl     = { "TCTL",     CMD_L_TYPE_TID,    mbx1_tctl    },
101         cif_poll     = { "POLL",     CMD_L_TYPE_NULL,   mbx1_poll    },
102 #ifdef OLD_BINARY_SUPPORT
103         /* v3.3 obsolete */
104         cif_wdt      = { "WDT",      CMD_L_TYPE_NULL,   mbx1_wdt     },
105 #endif
106         cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL         },
107         cif_pm       = { "PM",       CMD_L_TYPE_SUBCMD, NULL         },
108         cif_suspend  = { "SUSPEND",  CMD_L_TYPE_NULL,   mbx1_suspend },
109         cif_kfunc    = { "KFUNC",    CMD_L_TYPE_SUBCMD, mbx1_kfunc   },
110         cif_tcfg     = { "TCFG",     CMD_L_TYPE_TID,    mbx1_tcfg    },
111         cif_tadd     = { "TADD",     CMD_L_TYPE_TID,    mbx1_tadd    },
112         cif_tdel     = { "TDEL",     CMD_L_TYPE_TID,    mbx1_tdel    },
113         cif_tstop    = { "TSTOP",    CMD_L_TYPE_TID,    NULL         },
114         cif_dspcfg   = { "DSPCFG",   CMD_L_TYPE_SUBCMD, mbx1_dspcfg  },
115         cif_regrw    = { "REGRW",    CMD_L_TYPE_SUBCMD, mbx1_regrw   },
116         cif_getvar   = { "GETVAR",   CMD_L_TYPE_SUBCMD, mbx1_getvar  },
117         cif_setvar   = { "SETVAR",   CMD_L_TYPE_SUBCMD, NULL         },
118         cif_err      = { "ERR",      CMD_L_TYPE_SUBCMD, mbx1_err     },
119         cif_dbg      = { "DBG",      CMD_L_TYPE_NULL,   mbx1_dbg     };
120
121 const struct cmdinfo *cmdinfo[128] = {
122 /*00*/  &cif_null, &cif_null, &cif_null, &cif_null,
123         &cif_null, &cif_null, &cif_null, &cif_null,
124         &cif_null, &cif_null, &cif_null, &cif_null,
125         &cif_null, &cif_null, &cif_null, &cif_null,
126 /*10*/  &cif_wdsnd, &cif_wdreq, &cif_null, &cif_null,
127         &cif_null, &cif_null, &cif_null, &cif_null,
128         &cif_null, &cif_null, &cif_null, &cif_null,
129         &cif_null, &cif_null, &cif_null, &cif_null,
130 /*20*/  &cif_bksnd, &cif_bkreq, &cif_null, &cif_bkyld,
131         &cif_bksndp, &cif_bkreqp, &cif_null, &cif_null,
132         &cif_null, &cif_null, &cif_null, &cif_null,
133         &cif_null, &cif_null, &cif_null, &cif_null,
134 /*30*/  &cif_tctl, &cif_null, &cif_poll, &cif_null,
135         &cif_null, &cif_null, &cif_null, &cif_null,
136         &cif_null, &cif_null, &cif_null, &cif_null,
137         &cif_null, &cif_null, &cif_null, &cif_null,
138 /*40*/  &cif_null, &cif_null, &cif_null, &cif_null,
139         &cif_null, &cif_null, &cif_null, &cif_null,
140         &cif_null, &cif_null, &cif_null, &cif_null,
141         &cif_null, &cif_null, &cif_null, &cif_null,
142 #ifdef OLD_BINARY_SUPPORT
143         /* v3.3 obsolete */
144 /*50*/  &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend,
145 #else
146 /*50*/  &cif_null, &cif_runlevel, &cif_pm, &cif_suspend,
147 #endif
148         &cif_kfunc, &cif_null, &cif_null, &cif_null,
149         &cif_null, &cif_null, &cif_null, &cif_null,
150         &cif_null, &cif_null, &cif_null, &cif_null,
151 /*60*/  &cif_tcfg, &cif_null, &cif_tadd, &cif_tdel,
152         &cif_null, &cif_tstop, &cif_null, &cif_null,
153         &cif_null, &cif_null, &cif_null, &cif_null,
154         &cif_null, &cif_null, &cif_null, &cif_null,
155 /*70*/  &cif_dspcfg, &cif_null, &cif_regrw, &cif_null,
156         &cif_getvar, &cif_setvar, &cif_null, &cif_null,
157         &cif_err, &cif_dbg, &cif_null, &cif_null,
158         &cif_null, &cif_null, &cif_null, &cif_null
159 };
160
161 int sync_with_dsp(unsigned short *syncwd, unsigned short tid, int try_cnt)
162 {
163         int try;
164
165         if (*(volatile unsigned short *)syncwd == tid)
166                 return 0;
167
168         for (try = 0; try < try_cnt; try++) {
169                 udelay(1);
170                 if (*(volatile unsigned short *)syncwd == tid) {
171                         /* success! */
172                         printk(KERN_INFO
173                                "omapdsp: sync_with_dsp(): try = %d\n", try);
174                         return 0;
175                 }
176         }
177
178         /* fail! */
179         return -1;
180 }
181
182 static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt)
183 {
184         int cnt;
185
186         local_irq_save(*flags);
187         if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0)
188                 return 0;
189         /*
190          * mailbox is busy. wait for some usecs...
191          */
192         local_irq_restore(*flags);
193         for (cnt = 0; cnt < try_cnt; cnt++) {
194                 udelay(1);
195                 local_irq_save(*flags);
196                 if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0)     /* success! */
197                         return 0;
198                 local_irq_restore(*flags);
199         }
200
201         /* fail! */
202         return -1;
203 }
204
205 #ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
206 #define print_mb_busy_abort(mb) \
207         printk(KERN_DEBUG \
208                "mbx: mailbox is busy. %s is aborting.\n", cmd_name(*mb))
209 #define print_mb_mmu_abort(mb) \
210         printk(KERN_DEBUG \
211                "mbx: mmu interrupt is set. %s is aborting.\n", cmd_name(*mb))
212 #else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
213 #define print_mb_busy_abort(mb) do {} while(0)
214 #define print_mb_mmu_abort(mb)  do {} while(0)
215 #endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */
216
217 int __mbcmd_send(struct mbcmd *mb)
218 {
219         struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
220         unsigned long flags;
221
222         /*
223          * DSP mailbox interrupt latency must be less than 1ms.
224          */
225         if (mbsync_irq_save(&flags, 1000) < 0) {
226                 print_mb_busy_abort(mb);
227                 return -1;
228         }
229
230         if (mbseq) {
231                 mb->seq = mbseq->ad_arm;
232                 mbseq->ad_arm++;
233         } else
234                 mb->seq = 0;
235         mblog_add(mb, DIR_A2D);
236         mblog_printcmd(mb, DIR_A2D);
237
238         omap_writew(mb_hw->data, MAILBOX_ARM2DSP1);
239         omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b);
240
241         local_irq_restore(flags);
242         return 0;
243 }
244
245 /*
246  * __dsp_mbcmd_send(): mailbox dispatcher
247  */
248 int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
249 {
250         static DECLARE_MUTEX(mbsend_sem);
251         int ret = 0;
252
253         /*
254          * while MMU fault is set,
255          * only recovery command can be executed
256          */
257         if (dsp_err_mmu_isset() && !recovery_flag) {
258                 print_mb_mmu_abort(mb);
259                 return -1;
260         }
261
262         if (down_interruptible(&mbsend_sem) < 0)
263                 return -1;
264
265         if (arg) {      /* we have extra argument */
266                 int i;
267
268                 /*
269                  * even if ipbuf_sys_ad is in DSP internal memory, 
270                  * dsp_mem_enable() never cause to call PM mailbox command
271                  * because in that case DSP memory should be always enabled.
272                  * (see ipbuf_sys_hold_mem_active in ipbuf.c)
273                  *
274                  * Therefore, we can call this function here safely.
275                  */
276                 dsp_mem_enable(ipbuf_sys_ad);
277                 if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) {
278                         printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
279                         dsp_mem_disable(ipbuf_sys_ad);
280                         ret = -EBUSY;
281                         goto out;
282                 }
283                 for (i = 0; i < arg->argc; i++) {
284                         ipbuf_sys_ad->d[i] = arg->argv[i];
285                 }
286                 ipbuf_sys_ad->s = arg->tid;
287                 dsp_mem_disable(ipbuf_sys_ad);
288         }
289
290         ret = __mbcmd_send(mb);
291
292 out:
293         up(&mbsend_sem);
294         return ret;
295 }
296
297 int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
298                               wait_queue_head_t *q)
299 {
300         long current_state;
301         DECLARE_WAITQUEUE(wait, current);
302
303         add_wait_queue(q, &wait);
304         current_state = current->state;
305         set_current_state(TASK_INTERRUPTIBLE);
306         if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
307                 set_current_state(current_state);
308                 remove_wait_queue(q, &wait);
309                 return -1;
310         }
311         schedule_timeout(DSP_TIMEOUT);
312         set_current_state(current_state);
313         remove_wait_queue(q, &wait);
314
315         return 0;
316 }
317
318 int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
319                  int recovery_flag)
320 {
321         struct mbcmd mb;
322
323         mbcmd_set(mb, cmdh, cmdl, data);
324         return __dsp_mbcmd_send(&mb, NULL, recovery_flag);
325 }
326
327 static int mbsync_hold_mem_active;
328
329 void dsp_mb_start(void)
330 {
331         mbx1_valid = 1; /* start interpreting */
332         mbseq_expect_tmp = 0;
333 }
334
335 void dsp_mb_stop(void)
336 {
337         mbx1_valid = 0; /* stop interpreting */
338         if (mbsync_hold_mem_active) {
339                 dsp_mem_disable((void *)daram_base);
340                 mbsync_hold_mem_active = 0;
341         }
342         mbseq = NULL;
343         mbseq_expect = &mbseq_expect_tmp;
344 }
345
346 int dsp_mb_config(void *p)
347 {
348         unsigned long flags;
349
350         if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
351                 return -1;
352         if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
353                 printk(KERN_WARNING
354                        "omapdsp: mbseq is placed in DSP internal memory.\n"
355                        "         It will prevent DSP from idling.\n");
356                 mbsync_hold_mem_active = 1;
357                 /*
358                  * dsp_mem_enable() never fails because
359                  * it has been already enabled in dspcfg process and
360                  * this will just increment the usecount.
361                  */
362                 dsp_mem_enable((void *)daram_base);
363         }
364
365         local_irq_save(flags);
366         mbseq = p;
367         mbseq->da_arm = mbseq_expect_tmp;
368         mbseq_expect = &mbseq->da_arm;
369         local_irq_restore(flags);
370
371         return 0;
372 }
373
374 /*
375  * mbq: mailbox queue
376  */
377 #define MBQ_DEPTH       16
378 struct mbq {
379         struct mbcmd mb[MBQ_DEPTH];
380         int rp, wp, full;
381 } mbq = {
382         .rp = 0,
383         .wp = 0,
384 };
385
386 #define mbq_inc(p)      do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0)
387
388 /*
389  * workqueue for mbx1
390  */
391 static void do_mbx1(void)
392 {
393         int empty = 0;
394
395         disable_irq(INT_D2A_MB1);
396         if ((mbq.rp == mbq.wp) && !mbq.full)
397                 empty = 1;
398         enable_irq(INT_D2A_MB1);
399
400         while (!empty) {
401                 struct mbcmd *mb;
402
403                 mb = &mbq.mb[mbq.rp];
404
405                 mblog_add(mb, DIR_D2A);
406                 mblog_printcmd(mb, DIR_D2A);
407
408                 /*
409                  * call handler for each command
410                  */
411                 if (cmdinfo[mb->cmd_h]->handler)
412                         cmdinfo[mb->cmd_h]->handler(mb);
413                 else if (cmdinfo[mb->cmd_h] != &cif_null)
414                         printk(KERN_ERR "mbx: %s is not allowed from DSP.\n",
415                                cmd_name(*mb));
416                 else
417                         printk(KERN_ERR
418                                "mbx: Unrecognized command: "
419                                "cmd=0x%04x, data=0x%04x\n",
420                                ((struct mbcmd_hw *)mb)->cmd & 0x7fff, mb->data);
421
422                 disable_irq(INT_D2A_MB1);
423                 mbq_inc(mbq.rp);
424                 if (mbq.rp == mbq.wp)
425                         empty = 1;
426                 /* if mbq has been full, now we have a room. */
427                 if (mbq.full) {
428                         mbq.full = 0;
429                         enable_irq(INT_D2A_MB1);
430                 }
431                 enable_irq(INT_D2A_MB1);
432         }
433 }
434
435 static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL);
436
437 /*
438  * kernel function dispatcher
439  */
440 extern void mbx1_fbctl_disable(void);
441
442 static void mbx1_kfunc_fbctl(unsigned short data)
443 {
444         switch (data) {
445         case OMAP_DSP_MBCMD_FBCTL_DISABLE:
446                 mbx1_fbctl_disable();
447                 break;
448         default:
449                 printk(KERN_ERR
450                        "mailbox: Unknown FBCTL from DSP: 0x%04x\n", data);
451         }
452 }
453
454 static void mbx1_kfunc(struct mbcmd *mb)
455 {
456         switch (mb->cmd_l) {
457         case OMAP_DSP_MBCMD_KFUNC_FBCTL:
458                 mbx1_kfunc_fbctl(mb->data);
459                 break;
460
461         default:
462                 printk(KERN_ERR
463                        "mailbox: Unknown kfunc from DSP: 0x%02x\n", mb->cmd_l);
464         }
465 }
466
467 /*
468  * mailbox interrupt handler
469  */
470 static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
471 {
472         union {
473                 struct mbcmd sw;
474                 struct mbcmd_hw hw;
475         } *mb = (void *)&mbq.mb[mbq.wp];
476
477 #if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
478         mb->hw.data = omap_readw(MAILBOX_DSP2ARM1);
479         mb->hw.cmd  = omap_readw(MAILBOX_DSP2ARM1b);
480 #elif (INT_D2A_MB1 == INT_DSP_MAILBOX2)
481         mb->hw.data = omap_readw(MAILBOX_DSP2ARM2);
482         mb->hw.cmd  = omap_readw(MAILBOX_DSP2ARM2b);
483 #endif
484
485         /* if mbx1 has not been validated yet, discard. */
486         if (!mbx1_valid)
487                 return IRQ_HANDLED;
488
489         if (mb->sw.seq != (*mbseq_expect & 1)) {
490                 switch (mbseq_check_level) {
491                 case MBSEQ_CHECK_NONE:
492                         break;
493                 case MBSEQ_CHECK_VERBOSE:
494                         printk(KERN_INFO
495                                "mbx: illegal seq bit!!!  ignoring this command."
496                                " (%04x:%04x)\n", mb->hw.cmd, mb->hw.data);
497                         return IRQ_HANDLED;
498                 case MBSEQ_CHECK_SILENT:
499                         return IRQ_HANDLED;
500                 }
501         }
502
503         (*mbseq_expect)++;
504
505         mbq_inc(mbq.wp);
506         if (mbq.wp == mbq.rp) { /* mbq is full */
507                 mbq.full = 1;
508                 disable_irq(INT_D2A_MB1);
509         }
510         schedule_work(&mbx1_work);
511
512         return IRQ_HANDLED;
513 }
514
515 static irqreturn_t mbx2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
516 {
517         unsigned short cmd, data;
518
519 #if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
520         data = omap_readw(MAILBOX_DSP2ARM2);
521         cmd  = omap_readw(MAILBOX_DSP2ARM2b);
522 #elif (INT_D2A_MB1 == INT_DSP_MAILBOX2)
523         data = omap_readw(MAILBOX_DSP2ARM1);
524         cmd  = omap_readw(MAILBOX_DSP2ARM1b);
525 #endif
526         printk(KERN_DEBUG
527                "mailbox2 interrupt!  cmd=%04x, data=%04x\n", cmd, data);
528
529         return IRQ_HANDLED;
530 }
531
532 #if 0
533 static void mpuio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
534 {
535         printk(KERN_INFO "MPUIO interrupt!\n");
536 }
537 #endif
538
539 #ifdef CONFIG_PROC_FS
540 struct proc_dir_entry *procdir_dsp = NULL;
541
542 static void dsp_create_procdir_dsp(void)
543 {
544         procdir_dsp = proc_mkdir("dsp", 0);
545         if (procdir_dsp == NULL) {
546                 printk(KERN_ERR
547                        "omapdsp: failed to register proc directory: dsp\n");
548         }
549 }
550
551 static void dsp_remove_procdir_dsp(void)
552 {
553         procdir_dsp = NULL;
554         remove_proc_entry("dsp", 0);
555 }
556 #else /* CONFIG_PROC_FS */
557 #define dsp_create_procdir_dsp()        do { } while (0)
558 #define dsp_remove_procdir_dsp()        do { } while (0)
559 #endif /* CONFIG_PROC_FS */
560
561 extern irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id,
562                                      struct pt_regs *regs);
563
564 extern int  dsp_ctl_core_init(void);
565 extern void dsp_ctl_core_exit(void);
566 extern void dsp_ctl_init(void);
567 extern void dsp_ctl_exit(void);
568 extern int  dsp_mem_init(void);
569 extern void dsp_mem_exit(void);
570 extern void mblog_init(void);
571 extern void mblog_exit(void);
572 extern int  dsp_taskmod_init(void);
573 extern void dsp_taskmod_exit(void);
574
575 /*
576  * device functions
577  */
578 static void dsp_dev_release(struct device *dev)
579 {
580 }
581
582 /*
583  * driver functions
584  */
585 #if (INT_D2A_MB1 == INT_DSP_MAILBOX1)
586 #       define INT_D2A_MB2 INT_DSP_MAILBOX2
587 #elif(INT_D2A_MB1 == INT_DSP_MAILBOX2)  /* swap MB1 and MB2 */
588 #       define INT_D2A_MB2 INT_DSP_MAILBOX1
589 #endif
590
591 static int __init dsp_drv_probe(struct device *dev)
592 {
593         int ret;
594
595         printk(KERN_INFO "OMAP DSP driver initialization\n");
596
597         //__dsp_enable(); // XXX
598
599         dsp_create_procdir_dsp();
600
601         if ((ret = dsp_ctl_core_init()) < 0)
602                 goto fail1;
603         if ((ret = dsp_mem_init()) < 0)
604                 goto fail2;
605         dsp_ctl_init();
606         mblog_init();
607         if ((ret = dsp_taskmod_init()) < 0)
608                 goto fail3;
609
610         /*
611          * mailbox interrupt handlers registration
612          */
613         ret = request_irq(INT_D2A_MB1, mbx1_interrupt, SA_INTERRUPT, "dsp",
614                           dev);
615         if (ret) {
616                 printk(KERN_ERR
617                        "failed to register mailbox1 interrupt: %d\n", ret);
618                 goto fail4;
619         }
620
621         ret = request_irq(INT_D2A_MB2, mbx2_interrupt, SA_INTERRUPT, "dsp",
622                           dev);
623         if (ret) {
624                 printk(KERN_ERR
625                        "failed to register mailbox2 interrupt: %d\n", ret);
626                 goto fail5;
627         }
628
629         ret = request_irq(INT_DSP_MMU, dsp_mmu_interrupt, SA_INTERRUPT, "dsp",
630                           dev);
631         if (ret) {
632                 printk(KERN_ERR
633                        "failed to register DSP MMU interrupt: %d\n", ret);
634                 goto fail6;
635         }
636
637         /* MMU interrupt is not enabled until DSP runs */
638         disable_irq(INT_DSP_MMU);
639
640 #if 0
641         ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev);
642         if (ret) {
643                 printk(KERN_ERR
644                        "failed to register MPUIO interrupt: %d\n", ret);
645                 goto fail7;
646         }
647 #endif
648
649         return 0;
650
651 fail6:
652         free_irq(INT_D2A_MB2, dev);
653 fail5:
654         free_irq(INT_D2A_MB1, dev);
655 fail4:
656         dsp_taskmod_exit();
657 fail3:
658         mblog_exit();
659         dsp_ctl_exit();
660         dsp_mem_exit();
661 fail2:
662         dsp_ctl_core_exit();
663 fail1:
664         dsp_remove_procdir_dsp();
665
666         //__dsp_disable(); // XXX
667         return ret;
668 }
669
670 static int dsp_drv_remove(struct device *dev)
671 {
672         dsp_cpustat_request(CPUSTAT_RESET);
673
674 #if 0
675         free_irq(INT_MPUIO, dev);
676 #endif
677         free_irq(INT_DSP_MMU, dev);
678         free_irq(INT_D2A_MB2, dev);
679         free_irq(INT_D2A_MB1, dev);
680
681         /* recover disable_depth */
682         enable_irq(INT_DSP_MMU);
683
684         dspuncfg();
685         dsp_taskmod_exit();
686         mblog_exit();
687         dsp_ctl_exit();
688         dsp_mem_exit();
689
690         dsp_ctl_core_exit();
691         dsp_remove_procdir_dsp();
692
693         //__dsp_disable(); // XXX
694
695         return 0;
696 }
697
698 #ifdef CONFIG_PM
699 static int dsp_drv_suspend(struct device *dev, u32 state, u32 level)
700 {
701         switch(level) {
702         case SUSPEND_NOTIFY:
703         case SUSPEND_DISABLE:
704         case SUSPEND_SAVE_STATE:
705                 break;
706         case SUSPEND_POWER_DOWN:
707                 dsp_suspend();
708                 break;
709         }
710
711         return 0;
712 }
713
714 static int dsp_drv_resume(struct device *dev, u32 level)
715 {
716         switch(level) {
717         case RESUME_POWER_ON:
718                 dsp_resume();
719                 break;
720         case RESUME_RESTORE_STATE:
721         case RESUME_ENABLE:
722                 break;
723         }
724
725         return 0;
726 }
727 #endif /* CONFIG_PM */
728
729 static struct resource dsp_resources[] = {
730         {
731                 .start = INT_DSP_MAILBOX1,
732                 .flags = IORESOURCE_IRQ,
733         },
734         {
735                 .start = INT_DSP_MAILBOX2,
736                 .flags = IORESOURCE_IRQ,
737         },
738         {
739                 .start = INT_DSP_MMU,
740                 .flags = IORESOURCE_IRQ,
741         },
742 };
743
744 struct platform_device dsp_device = {
745         .name           = "dsp",
746         .id             = -1,
747         .dev = {
748                 .release        = dsp_dev_release,
749         },
750         .num_resources  = ARRAY_SIZE(&dsp_resources),
751         .resource       = dsp_resources,
752 };
753
754 static struct device_driver dsp_driver = {
755         .name           = "dsp",
756         .bus            = &platform_bus_type,
757         .probe          = dsp_drv_probe,
758         .remove         = dsp_drv_remove,
759 #ifdef CONFIG_PM
760         .suspend        = dsp_drv_suspend,
761         .resume         = dsp_drv_resume,
762 #endif
763 };
764
765 static int __init omap_dsp_mod_init(void)
766 {
767         int ret;
768
769         ret = platform_device_register(&dsp_device);
770         if (ret) {
771                 printk(KERN_ERR "failed to register the DSP device: %d\n", ret);
772                 goto fail1;
773         }
774
775         ret = driver_register(&dsp_driver);
776         if (ret) {
777                 printk(KERN_ERR "failed to register the DSP driver: %d\n", ret);
778                 goto fail2;
779         }
780
781         return 0;
782
783 fail2:
784         platform_device_unregister(&dsp_device);
785 fail1:
786         return -ENODEV;
787 }
788
789 static void __exit omap_dsp_mod_exit(void)
790 {
791         driver_unregister(&dsp_driver);
792         platform_device_unregister(&dsp_device);
793 }
794
795 module_init(omap_dsp_mod_init);
796 module_exit(omap_dsp_mod_exit);