]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/dsp_ctl.c
5738d143b736b3b129e7489f9fa0ad592eb6d786
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / dsp_ctl.c
1 /*
2  * linux/arch/arm/mach-omap/dsp/dsp_ctl.c
3  *
4  * OMAP DSP control device 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/09:  DSP Gateway version 3.3
25  */
26
27 #include <linux/module.h>
28 #include <linux/slab.h>
29 #include <linux/major.h>
30 #include <linux/fs.h>
31 #include <linux/device.h>
32 #include <linux/proc_fs.h>
33 #include <linux/init.h>
34 #include <linux/sched.h>
35 #include <linux/delay.h>
36 #include <linux/platform_device.h>
37 #include <asm/uaccess.h>
38 #include <asm/io.h>
39 #include <asm/ioctls.h>
40 #include <asm/hardware/clock.h>
41 #include <asm/arch/dsp.h>
42 #include "hardware_dsp.h"
43 #include "dsp.h"
44 #include "ipbuf.h"
45
46 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
47                              char *buf);
48 static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
49 extern struct device_attribute dev_attr_ipbuf;
50
51 static enum cfgstat {
52         CFG_ERR,
53         CFG_READY,
54         CFG_SUSPEND
55 } cfgstat;
56 int mbx_revision;
57 static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q);
58 static unsigned short ioctl_wait_cmd;
59 static DECLARE_MUTEX(ioctl_sem);
60
61 static unsigned char n_stask;
62
63 /*
64  * control functions
65  */
66 static short varread_val[5]; /* maximum */
67
68 static int dsp_regread(unsigned short cmd_l, unsigned short adr,
69                        unsigned short *val)
70 {
71         struct mbcmd mb;
72         int ret = 0;
73
74         if (down_interruptible(&ioctl_sem))
75                 return -ERESTARTSYS;
76
77         ioctl_wait_cmd = MBCMD(REGRW);
78         mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
79         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
80
81         if (ioctl_wait_cmd != 0) {
82                 printk(KERN_ERR "omapdsp: register read error!\n");
83                 ret = -EINVAL;
84                 goto up_out;
85         }
86
87         *val = varread_val[0];
88
89 up_out:
90         up(&ioctl_sem);
91         return ret;
92 }
93
94 static int dsp_regwrite(unsigned short cmd_l, unsigned short adr,
95                         unsigned short val)
96 {
97         struct mbcmd mb;
98         struct mb_exarg arg = {
99                 .tid  = OMAP_DSP_TID_ANON,
100                 .argc = 1,
101                 .argv = &val,
102         };
103
104         mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
105         dsp_mbcmd_send_exarg(&mb, &arg);
106         return 0;
107 }
108
109 static int dsp_getvar(unsigned char varid, unsigned short *val, int sz)
110 {
111         struct mbcmd mb;
112         int ret = 0;
113
114         if (down_interruptible(&ioctl_sem))
115                 return -ERESTARTSYS;
116
117         ioctl_wait_cmd = MBCMD(GETVAR);
118         mbcmd_set(mb, MBCMD(GETVAR), varid, 0);
119         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
120
121         if (ioctl_wait_cmd != 0) {
122                 printk(KERN_ERR "omapdsp: variable read error!\n");
123                 ret = -EINVAL;
124                 goto up_out;
125         }
126
127         memcpy(val, varread_val, sz * sizeof(short));
128
129 up_out:
130         up(&ioctl_sem);
131         return ret;
132 }
133
134 static int dsp_setvar(unsigned char varid, unsigned short val)
135 {
136         dsp_mbsend(MBCMD(SETVAR), varid, val);
137         return 0;
138 }
139
140 static int dspcfg(void)
141 {
142         struct mbcmd mb;
143         int ret = 0;
144
145         if (down_interruptible(&ioctl_sem))
146                 return -ERESTARTSYS;
147
148         if (cfgstat != CFG_ERR) {
149                 printk(KERN_ERR
150                        "omapdsp: DSP has been already configured. "
151                        "do unconfig!\n");
152                 ret = -EBUSY;
153                 goto up_out;
154         }
155
156         /* for safety */
157         dsp_mem_usecount_clear();
158
159         /*
160          * DSPCFG command and dsp_mem_start() must be called
161          * while internal mem is on.
162          */
163         dsp_mem_enable((void *)dspmem_base);
164
165         dsp_mb_start();
166         dsp_twch_start();
167         dsp_mem_start();
168         dsp_err_start();
169
170         mbx_revision = -1;
171         ioctl_wait_cmd = MBCMD(DSPCFG);
172         mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0);
173         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
174
175         if (ioctl_wait_cmd != 0) {
176                 printk(KERN_ERR "omapdsp: configuration error!\n");
177                 ret = -EINVAL;
178                 cfgstat = CFG_ERR;
179                 goto up_out;
180         }
181
182 #ifdef OLD_BINARY_SUPPORT
183         /*
184          * MBREV 3.2 or earlier doesn't assume DMA domain is on
185          * when DSPCFG command is sent
186          */
187         if ((mbx_revision == MBREV_3_0) ||
188             (mbx_revision == MBREV_3_2)) {
189                 ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
190                                  DSPREG_ICR_DMA_IDLE_DOMAIN);
191         }
192 #endif
193
194         if ((ret = dsp_task_config_all(n_stask)) < 0) {
195                 up(&ioctl_sem);
196                 dspuncfg();
197                 dsp_mem_disable((void *)dspmem_base);
198                 return -EINVAL;
199         }
200
201         cfgstat = CFG_READY;
202
203         /* send parameter */
204         if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK,
205                               dsp_cpustat_get_icrmask())) < 0)
206                 goto up_out;
207
208         /* create runtime sysfs entries */
209         device_create_file(&dsp_device.dev, &dev_attr_loadinfo);
210         device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
211
212 up_out:
213         dsp_mem_disable((void *)dspmem_base);
214         up(&ioctl_sem);
215         return ret;
216 }
217
218 int dspuncfg(void)
219 {
220         if (dsp_taskmod_busy()) {
221                 printk(KERN_WARNING "omapdsp: tasks are busy.\n");
222                 return -EBUSY;
223         }
224
225         if (down_interruptible(&ioctl_sem))
226                 return -ERESTARTSYS;
227
228         /* FIXME: lock task module */
229
230         /* remove runtime sysfs entries */
231         device_remove_file(&dsp_device.dev, &dev_attr_loadinfo);
232         device_remove_file(&dsp_device.dev, &dev_attr_ipbuf);
233
234         dsp_mb_stop();
235         dsp_twch_stop();
236         dsp_mem_stop();
237         dsp_err_stop();
238         dsp_dbg_stop();
239         dsp_task_unconfig_all();
240         ipbuf_stop();
241         cfgstat = CFG_ERR;
242
243         up(&ioctl_sem);
244         return 0;
245 }
246
247 int dsp_is_ready(void)
248 {
249         return (cfgstat == CFG_READY) ? 1 : 0;
250 }
251
252 /*
253  * polls all tasks
254  */
255 int dsp_poll(void)
256 {
257         struct mbcmd mb;
258         int ret = 0;
259
260         if (down_interruptible(&ioctl_sem))
261                 return -ERESTARTSYS;
262
263         ioctl_wait_cmd = MBCMD(POLL);
264         mbcmd_set(mb, MBCMD(POLL), 0, 0);
265         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
266
267         if (ioctl_wait_cmd != 0) {
268                 printk(KERN_ERR "omapdsp: poll error!\n");
269                 ret = -EINVAL;
270                 goto up_out;
271         }
272
273 up_out:
274         up(&ioctl_sem);
275         return ret;
276 }
277
278 void dsp_runlevel(unsigned char level)
279 {
280         if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY)
281                 dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0);
282         else
283                 dsp_mbsend(MBCMD(RUNLEVEL), level, 0);
284 }
285
286 static enum cfgstat cfgstat_save_suspend;
287
288 /*
289  * suspend / resume callbacks
290  * DSP is not reset within this code, but done in omap_pm_suspend.
291  * so if these functions are called as OMAP_DSP_IOCTL_SUSPEND,
292  * DSP should be reset / unreset out of these functions.
293  */
294 int dsp_suspend(void)
295 {
296         struct mbcmd mb;
297         int ret = 0;
298
299         if (cfgstat == CFG_SUSPEND) {
300                 printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n");
301                 return -EINVAL;
302         }
303
304         if (down_interruptible(&ioctl_sem))
305                 return -ERESTARTSYS;
306
307         cfgstat_save_suspend = cfgstat;
308         if (!dsp_is_ready()) {
309                 if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
310                         printk(KERN_WARNING
311                                "omapdsp: illegal operation: trying suspend DSP "
312                                "while it is running but has not configured "
313                                "yet.\n"
314                                "  Resetting DSP...\n");
315                 }
316                 goto transition;
317         }
318
319         ioctl_wait_cmd = MBCMD(SUSPEND);
320         mbcmd_set(mb, MBCMD(SUSPEND), 0, 0);
321         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
322
323         if (ioctl_wait_cmd != 0) {
324                 printk(KERN_ERR "omapdsp: DSP suspend error!\n");
325                 ret = -EINVAL;
326                 goto up_out;
327         }
328
329         udelay(100);
330 transition:
331         cfgstat = CFG_SUSPEND;
332 up_out:
333         up(&ioctl_sem);
334         return ret;
335 }
336
337 int dsp_resume(void)
338 {
339         if (cfgstat != CFG_SUSPEND) {
340                 printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n");
341                 return -EINVAL;
342         }
343
344         cfgstat = cfgstat_save_suspend;
345         return 0;
346 }
347
348 static void dsp_fbctl_enable(void)
349 {
350         dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
351                    OMAP_DSP_MBCMD_FBCTL_ENABLE);
352 }
353
354 static int dsp_fbctl_disable(void)
355 {
356         int ret = 0;
357         struct mbcmd mb;
358
359         if (down_interruptible(&ioctl_sem))
360                 return -ERESTARTSYS;
361
362         ioctl_wait_cmd = MBCMD(KFUNC);
363         mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
364                   OMAP_DSP_MBCMD_FBCTL_DISABLE);
365         dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
366         if (ioctl_wait_cmd != 0) {
367                 printk(KERN_ERR "omapdsp: fb disable error!\n");
368                 ret = -EINVAL;
369         }
370         up(&ioctl_sem);
371
372         return ret;
373 }
374
375 /*
376  * DSP control device file operations
377  */
378 static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
379                          unsigned int cmd, unsigned long arg)
380 {
381         int ret = 0;
382
383         switch (cmd) {
384         /*
385          * command level 1: commands which don't need lock
386          */
387         case OMAP_DSP_IOCTL_RUN:
388                 dsp_cpustat_request(CPUSTAT_RUN);
389                 break;
390
391         case OMAP_DSP_IOCTL_RESET:
392                 dsp_cpustat_request(CPUSTAT_RESET);
393                 break;
394
395         case OMAP_DSP_IOCTL_SETRSTVECT:
396                 ret = dsp_set_rstvect((unsigned long)arg);
397                 break;
398
399         case OMAP_DSP_IOCTL_CPU_IDLE:
400                 dsp_cpustat_request(CPUSTAT_CPU_IDLE);
401                 break;
402
403         case OMAP_DSP_IOCTL_GBL_IDLE:
404                 dsp_cpustat_request(CPUSTAT_GBL_IDLE);
405                 break;
406
407         case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON:
408                 mpui_wordswap_on();
409                 break;
410
411         case OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF:
412                 mpui_wordswap_off();
413                 break;
414
415         case OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON:
416                 mpui_byteswap_on();
417                 break;
418
419         case OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF:
420                 mpui_byteswap_off();
421                 break;
422
423         case OMAP_DSP_IOCTL_MBSEND:
424                 {
425                         struct omap_dsp_mailbox_cmd u_cmd;
426                         struct mbcmd_hw mb;
427                         if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
428                                 return -EFAULT;
429                         mb.cmd  = u_cmd.cmd;
430                         mb.data = u_cmd.data;
431                         ret = dsp_mbcmd_send((struct mbcmd *)&mb);
432                         break;
433                 }
434
435         case OMAP_DSP_IOCTL_SETVAR:
436                 {
437                         struct omap_dsp_varinfo var;
438                         if (copy_from_user(&var, (void *)arg, sizeof(var)))
439                                 return -EFAULT;
440                         ret = dsp_setvar(var.varid, var.val[0]);
441                         break;
442                 }
443
444         case OMAP_DSP_IOCTL_RUNLEVEL:
445                 dsp_runlevel(arg);
446                 break;
447
448         case OMAP_DSP_IOCTL_FBEN:
449                 dsp_fbctl_enable();
450                 return 0;
451
452         /*
453          * command level 2: commands which need lock
454          */
455         case OMAP_DSP_IOCTL_DSPCFG:
456                 ret = dspcfg();
457                 break;
458
459         case OMAP_DSP_IOCTL_DSPUNCFG:
460                 ret = dspuncfg();
461                 break;
462
463         case OMAP_DSP_IOCTL_TASKCNT:
464                 ret = dsp_task_count();
465                 break;
466
467         case OMAP_DSP_IOCTL_POLL:
468                 ret = dsp_poll();
469                 break;
470
471         case OMAP_DSP_IOCTL_FBDIS:
472                 ret = dsp_fbctl_disable();
473                 break;
474
475         /*
476          * FIXME: cpu status control for suspend - resume
477          */
478         case OMAP_DSP_IOCTL_SUSPEND:
479                 if ((ret = dsp_suspend()) < 0)
480                         break;
481                 dsp_cpustat_request(CPUSTAT_RESET);
482                 break;
483
484         case OMAP_DSP_IOCTL_RESUME:
485                 if ((ret = dsp_resume()) < 0)
486                         break;
487                 dsp_cpustat_request(CPUSTAT_RUN);
488                 break;
489
490         case OMAP_DSP_IOCTL_REGMEMR:
491                 {
492                         struct omap_dsp_reginfo *u_reg = (void *)arg;
493                         unsigned short adr, val;
494
495                         if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
496                                 return -EFAULT;
497                         if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_MEMR,
498                                                adr, &val)) < 0)
499                                 return ret;
500                         if (copy_to_user(&u_reg->val, &val, sizeof(short)))
501                                 return -EFAULT;
502                         break;
503                 }
504
505         case OMAP_DSP_IOCTL_REGMEMW:
506                 {
507                         struct omap_dsp_reginfo reg;
508
509                         if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
510                                 return -EFAULT;
511                         ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_MEMW,
512                                            reg.adr, reg.val);
513                         break;
514                 }
515
516         case OMAP_DSP_IOCTL_REGIOR:
517                 {
518                         struct omap_dsp_reginfo *u_reg = (void *)arg;
519                         unsigned short adr, val;
520
521                         if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
522                                 return -EFAULT;
523                         if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_IOR,
524                                                adr, &val)) < 0)
525                                 return ret;
526                         if (copy_to_user(&u_reg->val, &val, sizeof(short)))
527                                 return -EFAULT;
528                         break;
529                 }
530
531         case OMAP_DSP_IOCTL_REGIOW:
532                 {
533                         struct omap_dsp_reginfo reg;
534
535                         if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
536                                 return -EFAULT;
537                         ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_IOW,
538                                            reg.adr, reg.val);
539                         break;
540                 }
541
542         case OMAP_DSP_IOCTL_GETVAR:
543                 {
544                         struct omap_dsp_varinfo *u_var = (void *)arg;
545                         unsigned char varid;
546                         unsigned short val[5]; /* maximum */
547                         int argc;
548
549                         if (copy_from_user(&varid, &u_var->varid, sizeof(char)))
550                                 return -EFAULT;
551                         switch (varid) {
552                         case OMAP_DSP_MBCMD_VARID_ICRMASK:
553                                 argc = 1;
554                                 break;
555                         case OMAP_DSP_MBCMD_VARID_LOADINFO:
556                                 argc = 5;
557                                 break;
558                         default:
559                                 return -EINVAL;
560                         }
561                         if ((ret = dsp_getvar(varid, val, argc)) < 0)
562                                 return ret;
563                         if (copy_to_user(&u_var->val, val, sizeof(short) * argc))
564                                 return -EFAULT;
565                         break;
566                 }
567
568         default:
569                 return -ENOIOCTLCMD;
570         }
571
572         return ret;
573 }
574
575 /*
576  * functions called from mailbox1 interrupt routine
577  */
578 void mbx1_suspend(struct mbcmd *mb)
579 {
580         if (!waitqueue_active(&ioctl_wait_q) ||
581             (ioctl_wait_cmd != MBCMD(SUSPEND))) {
582                 printk(KERN_WARNING
583                        "mbx: SUSPEND command received, "
584                        "but nobody is waiting for it...\n");
585                 return;
586         }
587
588         ioctl_wait_cmd = 0;
589         wake_up_interruptible(&ioctl_wait_q);
590 }
591
592 void mbx1_dspcfg(struct mbcmd *mb)
593 {
594         unsigned char last   = mb->cmd_l & 0x80;
595         unsigned char cfgcmd = mb->cmd_l & 0x7f;
596         static unsigned long tmp_ipb_adr;
597
598         /* mailbox protocol check */
599         if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) {
600                 if (!waitqueue_active(&ioctl_wait_q) ||
601                     (ioctl_wait_cmd != MBCMD(DSPCFG))) {
602                         printk(KERN_WARNING
603                                "mbx: DSPCFG command received, "
604                                "but nobody is waiting for it...\n");
605                         return;
606                 }
607
608                 mbx_revision = mb->data;
609                 if (mbx_revision == OMAP_DSP_MBPROT_REVISION)
610                         return;
611 #ifdef OLD_BINARY_SUPPORT
612                 else if ((mbx_revision == MBREV_3_0) ||
613                          (mbx_revision == MBREV_3_2)) {
614                         printk(KERN_WARNING
615                                "mbx: ***** old DSP binary *****\n"
616                                "  Please update your DSP application.\n");
617                         return;
618                 }
619 #endif
620                 else {
621                         printk(KERN_ERR
622                                "mbx: protocol revision check error!\n"
623                                "  expected=0x%04x, received=0x%04x\n",
624                                OMAP_DSP_MBPROT_REVISION, mb->data);
625                         mbx_revision = -1;
626                         goto abort1;
627                 }
628         }
629
630         /*
631          * following commands are accepted only after
632          * revision check has been passed.
633          */
634         if (!mbx_revision < 0) {
635                 printk(KERN_INFO
636                        "mbx: DSPCFG command received, "
637                        "but revision check has not been passed.\n");
638                 return;
639         }
640
641         if (!waitqueue_active(&ioctl_wait_q) ||
642             (ioctl_wait_cmd != MBCMD(DSPCFG))) {
643                 printk(KERN_WARNING
644                        "mbx: DSPCFG command received, "
645                        "but nobody is waiting for it...\n");
646                 return;
647         }
648
649         switch (cfgcmd) {
650         case OMAP_DSP_MBCMD_DSPCFG_SYSADRH:
651                 tmp_ipb_adr = (unsigned long)mb->data << 16;
652                 break;
653
654         case OMAP_DSP_MBCMD_DSPCFG_SYSADRL:
655                 tmp_ipb_adr |= mb->data;
656                 break;
657
658         case OMAP_DSP_MBCMD_DSPCFG_ABORT:
659                 goto abort1;
660
661         default:
662                 printk(KERN_ERR
663                        "mbx: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
664                        mb->cmd_l, mb->data);
665                 return;
666         }
667
668         if (last) {
669                 void *badr;
670                 unsigned short bln;
671                 unsigned short bsz;
672                 volatile unsigned short *buf;
673                 void *ipb_sys_da, *ipb_sys_ad;
674                 void *mbseq;
675                 short *dbg_buf;
676                 unsigned short dbg_buf_sz, dbg_line_sz;
677                 struct mem_sync_struct mem_sync, *mem_syncp;
678
679                 ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
680                 if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
681                         goto abort1;
682
683                 if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
684                         printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n");
685                         goto abort1;
686                 }
687                 /*
688                  * read configuration data on system IPBUF
689                  * we must read with 16bit-access
690                  */
691 #ifdef OLD_BINARY_SUPPORT
692                 if (mbx_revision == OMAP_DSP_MBPROT_REVISION) {
693 #endif
694                         buf = ipbuf_sys_da->d;
695                         n_stask        = buf[0];
696                         bln            = buf[1];
697                         bsz            = buf[2];
698                         badr           = MKVIRT(buf[3], buf[4]);
699                         /* ipb_sys_da     = MKVIRT(buf[5], buf[6]); */
700                         ipb_sys_ad     = MKVIRT(buf[7], buf[8]);
701                         mbseq          = MKVIRT(buf[9], buf[10]);
702                         dbg_buf        = MKVIRT(buf[11], buf[12]);
703                         dbg_buf_sz     = buf[13];
704                         dbg_line_sz    = buf[14];
705                         mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
706                         mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
707                         mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
708                         mem_syncp = &mem_sync;
709 #ifdef OLD_BINARY_SUPPORT
710                 } else if (mbx_revision == MBREV_3_2) {
711                         buf = ipbuf_sys_da->d;
712                         n_stask     = buf[0];
713                         bln         = buf[1];
714                         bsz         = buf[2];
715                         badr        = MKVIRT(buf[3], buf[4]);
716                         /* ipb_sys_da  = MKVIRT(buf[5], buf[6]); */
717                         ipb_sys_ad  = MKVIRT(buf[7], buf[8]);
718                         mbseq       = MKVIRT(buf[9], buf[10]);
719                         dbg_buf     = NULL;
720                         dbg_buf_sz  = 0;
721                         dbg_line_sz = 0;
722                         mem_syncp   = NULL;
723                 } else if (mbx_revision == MBREV_3_0) {
724                         buf = ipbuf_sys_da->d;
725                         n_stask     = buf[0];
726                         bln         = buf[1];
727                         bsz         = buf[2];
728                         badr        = MKVIRT(buf[3], buf[4]);
729                         /* bkeep       = buf[5]; */
730                         /* ipb_sys_da  = MKVIRT(buf[6], buf[7]); */
731                         ipb_sys_ad  = MKVIRT(buf[8], buf[9]);
732                         mbseq       = MKVIRT(buf[10], buf[11]);
733                         dbg_buf     = NULL;
734                         dbg_buf_sz  = 0;
735                         dbg_line_sz = 0;
736                         mem_syncp   = NULL;
737                 } else /* should not occur */
738                         goto abort1;
739 #endif /* OLD_BINARY_SUPPORT */
740
741                 release_ipbuf_pvt(ipbuf_sys_da);
742
743                 /*
744                  * following configurations need to be done before
745                  * waking up the dspcfg initiator process.
746                  */
747                 if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
748                         goto abort1;
749                 if (ipbuf_config(bln, bsz, badr) < 0)
750                         goto abort1;
751                 if (dsp_mb_config(mbseq) < 0)
752                         goto abort2;
753                 if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
754                         goto abort2;
755                 if (dsp_mem_sync_config(mem_syncp) < 0)
756                         goto abort2;
757
758                 ioctl_wait_cmd = 0;
759                 wake_up_interruptible(&ioctl_wait_q);
760         }
761         return;
762
763 abort2:
764         ipbuf_stop();
765 abort1:
766         wake_up_interruptible(&ioctl_wait_q);
767         return;
768 }
769
770 void mbx1_poll(struct mbcmd *mb)
771 {
772         if (!waitqueue_active(&ioctl_wait_q) ||
773             (ioctl_wait_cmd != MBCMD(POLL))) {
774                 printk(KERN_WARNING
775                        "mbx: POLL command received, "
776                        "but nobody is waiting for it...\n");
777                 return;
778         }
779
780         ioctl_wait_cmd = 0;
781         wake_up_interruptible(&ioctl_wait_q);
782 }
783
784 void mbx1_regrw(struct mbcmd *mb)
785 {
786         if (!waitqueue_active(&ioctl_wait_q) ||
787             (ioctl_wait_cmd != MBCMD(REGRW))) {
788                 printk(KERN_WARNING
789                        "mbx: REGRW command received, "
790                        "but nobody is waiting for it...\n");
791                 return;
792         }
793
794         switch (mb->cmd_l) {
795         case OMAP_DSP_MBCMD_REGRW_DATA:
796                 ioctl_wait_cmd = 0;
797                 varread_val[0] = mb->data;
798                 wake_up_interruptible(&ioctl_wait_q);
799                 return;
800
801         default:
802                 printk(KERN_ERR
803                        "mbx: Illegal REGRW command: "
804                        "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
805                 return;
806         }
807 }
808
809 void mbx1_getvar(struct mbcmd *mb)
810 {
811         unsigned char varid = mb->cmd_l;
812         int i;
813         volatile unsigned short *buf;
814
815         if (!waitqueue_active(&ioctl_wait_q) ||
816             (ioctl_wait_cmd != MBCMD(GETVAR))) {
817                 printk(KERN_WARNING
818                        "mbx: GETVAR command received, "
819                        "but nobody is waiting for it...\n");
820                 return;
821         }
822
823         ioctl_wait_cmd = 0;
824         switch (varid) {
825         case OMAP_DSP_MBCMD_VARID_ICRMASK:
826                 varread_val[0] = mb->data;
827                 break;
828         case OMAP_DSP_MBCMD_VARID_LOADINFO:
829                 {
830                         if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
831                                 printk(KERN_ERR
832                                        "mbx: GETVAR - IPBUF sync failed!\n");
833                                 return;
834                         }
835                         /* need word access. do not use memcpy. */
836                         buf = ipbuf_sys_da->d;
837                         for (i = 0; i < 5; i++) {
838                                 varread_val[i] = buf[i];
839                         }
840                         release_ipbuf_pvt(ipbuf_sys_da);
841                         break;
842                 }
843         }
844         wake_up_interruptible(&ioctl_wait_q);
845
846         return;
847 }
848
849 /*
850  * sysfs files
851  */
852 static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
853                           char *buf)
854 {
855         int len = 0;
856
857         /*
858          * I/F VERSION descriptions:
859          *
860          * 3.2: sysfs / udev support
861          *      KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
862          * 3.3: added following ioctls
863          *      OMAP_DSP_IOCTL_GBL_IDLE
864          *      OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE)
865          *      OMAP_DSP_IOCTL_POLL
866          */
867
868         /*
869          * print all supporting I/F VERSIONs, like followings.
870          *
871          * len += sprintf(buf, "3.2\n");
872          * len += sprintf(buf, "3.3\n");
873          */
874         len += sprintf(buf + len, "3.2\n");
875         len += sprintf(buf + len, "3.3\n");
876
877         return len;
878 }
879
880 static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
881
882 static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
883                             char *buf)
884 {
885         return sprintf(buf, "%s\n", cpustat_name(dsp_cpustat_get_stat()));
886 }
887
888 static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
889
890 static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
891                             char *buf)
892 {
893         return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
894 }
895
896 static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
897                              const char *buf, size_t count)
898 {
899         unsigned short mask;
900         int ret;
901
902         if (!capable(CAP_SYS_ADMIN))
903                 return -EPERM;
904
905         mask = simple_strtol(buf, NULL, 16);
906         dsp_cpustat_set_icrmask(mask);
907
908         if (dsp_is_ready()) {
909                 ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask);
910                 if (ret < 0)
911                         return ret;
912         }
913
914         return strlen(buf);
915 }
916
917 static struct device_attribute dev_attr_icrmask = 
918         __ATTR(icrmask, S_IWUSR | S_IRUGO, icrmask_show, icrmask_store);
919
920 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
921                              char *buf)
922 {
923         int len;
924         int ret;
925         static unsigned short val[5];
926
927         if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_LOADINFO, val, 5)) < 0)
928                 return ret;
929
930         /* load info value range is 0(free) - 10000(busy) */
931         len = sprintf(buf,
932                       "DSP load info:\n"
933                       "  10ms average = %3d.%02d%%\n"
934                       "  1sec average = %3d.%02d%%  busiest 10ms = %3d.%02d%%\n"
935                       "  1min average = %3d.%02d%%  busiest 1s   = %3d.%02d%%\n",
936                       val[0]/100, val[0]%100,
937                       val[1]/100, val[1]%100, val[2]/100, val[2]%100,
938                       val[3]/100, val[3]%100, val[4]/100, val[4]%100);
939         return len;
940 }
941
942 /*
943  * This is declared at the top of this file.
944  *
945  * static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
946  */
947
948 void mbx1_fbctl_disable(void)
949 {
950         if (!waitqueue_active(&ioctl_wait_q) ||
951             (ioctl_wait_cmd != MBCMD(KFUNC))) {
952                 printk(KERN_WARNING
953                        "mbx: KFUNC:FBCTL command received, "
954                        "but nobody is waiting for it...\n");
955                 return;
956         }
957         ioctl_wait_cmd = 0;
958         wake_up_interruptible(&ioctl_wait_q);
959 }
960
961 #ifdef CONFIG_PROC_FS
962 /* for backward compatibility */
963 static int version_read_proc(char *page, char **start, off_t off, int count,
964                              int *eof, void *data)
965 {
966         /*
967          * This entry is read by 3.1 tools only, so leave it as is.
968          * 3.2 and later will read from sysfs file.
969          */
970         return sprintf(page, "3.1\n");
971 }
972
973 static void __init dsp_ctl_create_proc(void)
974 {
975         struct proc_dir_entry *ent;
976
977         /* version */
978         ent = create_proc_read_entry("version", 0, procdir_dsp,
979                                      version_read_proc, NULL);
980         if (ent == NULL) {
981                 printk(KERN_ERR
982                        "omapdsp: failed to register proc device: version\n");
983         }
984 }
985
986 static void dsp_ctl_remove_proc(void)
987 {
988         remove_proc_entry("version", procdir_dsp);
989 }
990 #endif /* CONFIG_PROC_FS */
991
992 struct file_operations dsp_ctl_fops = {
993         .owner   = THIS_MODULE,
994         .ioctl   = dsp_ctl_ioctl,
995 };
996
997 void __init dsp_ctl_init(void)
998 {
999         device_create_file(&dsp_device.dev, &dev_attr_ifver);
1000         device_create_file(&dsp_device.dev, &dev_attr_cpustat);
1001         device_create_file(&dsp_device.dev, &dev_attr_icrmask);
1002 #ifdef CONFIG_PROC_FS
1003         dsp_ctl_create_proc();
1004 #endif
1005 }
1006
1007 void dsp_ctl_exit(void)
1008 {
1009         device_remove_file(&dsp_device.dev, &dev_attr_ifver);
1010         device_remove_file(&dsp_device.dev, &dev_attr_cpustat);
1011         device_remove_file(&dsp_device.dev, &dev_attr_icrmask);
1012 #ifdef CONFIG_PROC_FS
1013         dsp_ctl_remove_proc();
1014 #endif
1015 }