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