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