]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/dsp/dspgateway/dsp_ctl.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / drivers / dsp / dspgateway / dsp_ctl.c
1 /*
2  * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
3  *
4  * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/module.h>
25 #include <linux/fs.h>
26 #include <linux/device.h>
27 #include <linux/init.h>
28 #include <linux/sched.h>
29 #include <linux/delay.h>
30 #include <linux/platform_device.h>
31 #include <linux/clk.h>
32 #include <linux/mutex.h>
33 #include <asm/uaccess.h>
34 #include <asm/io.h>
35 #include <asm/ioctls.h>
36 #include <mach/mailbox.h>
37 #include <mach/dsp.h>
38 #include "hardware_dsp.h"
39 #include "dsp_mbcmd.h"
40 #include "dsp.h"
41 #include "ipbuf.h"
42
43 enum dsp_space_e {
44         SPACE_MEM,
45         SPACE_IO,
46 };
47
48 #ifdef CONFIG_OMAP_DSP_FBEXPORT
49 static enum fbstat_e {
50         FBSTAT_DISABLED = 0,
51         FBSTAT_ENABLED,
52         FBSTAT_MAX,
53 } fbstat = FBSTAT_ENABLED;
54 #endif
55
56 static enum cfgstat_e cfgstat;
57 int mbox_revision;
58 static u8 n_stask;
59
60 static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
61                           char *buf);
62 static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
63                             char *buf);
64 static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
65                             char *buf);
66 static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
67                              const char *buf, size_t count);
68 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
69                              char *buf);
70
71 #define __ATTR_RW(_name, _mode) { \
72         .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
73         .show   = _name##_show,                                 \
74         .store  = _name##_store,                                        \
75 }
76
77 static struct device_attribute dev_attr_ifver     = __ATTR_RO(ifver);
78 static struct device_attribute dev_attr_cpustat   = __ATTR_RO(cpustat);
79 static struct device_attribute dev_attr_icrmask   = __ATTR_RW(icrmask, 0644);
80 static struct device_attribute dev_attr_loadinfo  = __ATTR_RO(loadinfo);
81
82 /*
83  * misc interactive mailbox command operations
84  */
85 static struct misc_mb_wait_struct {
86         struct mutex lock;
87         wait_queue_head_t wait_q;
88         u8 cmd_h;
89         u8 cmd_l;
90         u16 *retvp;
91 } misc_mb_wait = {
92         .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
93         .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
94 };
95
96 static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
97                                           u16 *retvp)
98 {
99         struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
100         int ret = 0;
101
102         if (mutex_lock_interruptible(&misc_mb_wait.lock))
103                 return -EINTR;
104
105         misc_mb_wait.cmd_h = mb.cmd_h;
106         misc_mb_wait.cmd_l = mb.cmd_l;
107         misc_mb_wait.retvp = retvp;
108         dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
109
110         if (misc_mb_wait.cmd_h != 0)
111                 ret = -EINVAL;
112
113         mutex_unlock(&misc_mb_wait.lock);
114         return ret;
115 }
116
117 #define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
118                 __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
119                                                (data), (retvp));
120
121 static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
122 {
123         volatile u16 *buf;
124         int i;
125
126         /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
127         if (!waitqueue_active(&misc_mb_wait.wait_q) ||
128             (misc_mb_wait.cmd_h != mb->cmd_h) ||
129             (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
130                 const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
131                 char cmdstr[32];
132
133                 if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
134                         sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
135                 else
136                         strcpy(cmdstr, ci->name);
137                 printk(KERN_WARNING
138                        "mbox: unexpected command %s received!\n", cmdstr);
139                 return -1;
140         }
141
142         /*
143          * if argc == 1, receive data through mbox:data register.
144          * if argc > 1, receive through ipbuf_sys.
145          */
146         if (argc == 1)
147                 misc_mb_wait.retvp[0] = mb->data;
148         else if (argc > 1) {
149                 if (dsp_mem_enable(ipbuf_sys_da) < 0) {
150                         printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
151                                cmdinfo[mb->cmd_h]->name);
152                         return -1;
153                 }
154                 if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
155                         printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
156                                cmdinfo[mb->cmd_h]->name);
157                         dsp_mem_disable(ipbuf_sys_da);
158                         return -1;
159                 }
160                 /* need word access. do not use memcpy. */
161                 buf = ipbuf_sys_da->d;
162                 for (i = 0; i < argc; i++)
163                         misc_mb_wait.retvp[i] = buf[i];
164                 release_ipbuf_pvt(ipbuf_sys_da);
165                 dsp_mem_disable(ipbuf_sys_da);
166         }
167
168         misc_mb_wait.cmd_h = 0;
169         wake_up_interruptible(&misc_mb_wait.wait_q);
170         return 0;
171 }
172
173 static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
174 {
175         u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
176         int ret;
177
178         ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
179         if ((ret < 0) && (ret != -EINTR))
180                 printk(KERN_ERR "omapdsp: register read error!\n");
181
182         return ret;
183 }
184
185 static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
186 {
187         u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
188         struct mb_exarg arg = {
189                 .tid  = TID_ANON,
190                 .argc = 1,
191                 .argv = &val,
192         };
193
194         mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
195         return 0;
196 }
197
198 static int dsp_getvar(u8 varid, u16 *val)
199 {
200         int ret;
201
202         ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
203         if ((ret < 0) && (ret != -EINTR))
204                 printk(KERN_ERR "omapdsp: variable read error!\n");
205
206         return ret;
207 }
208
209 static int dsp_setvar(u8 varid, u16 val)
210 {
211         mbcompose_send(SETVAR, varid, val);
212         return 0;
213 }
214
215 /*
216  * dsp_cfg() return value
217  *  = 0: OK
218  *  = 1: failed, but state is clear. (DSPCFG command failed)
219  *  < 0: failed. need cleanup.
220  */
221 static int dsp_cfg(void)
222 {
223         int ret = 0;
224
225 #ifdef CONFIG_ARCH_OMAP1
226         /* for safety */
227         dsp_mem_usecount_clear();
228 #endif
229
230         /*
231          * DSPCFG command and dsp_mem_start() must be called
232          * while internal mem is on.
233          */
234         dsp_mem_enable((void *)dspmem_base);
235
236         dsp_mbox_start();
237         dsp_twch_start();
238         dsp_mem_start();
239         dsp_err_start();
240
241         mbox_revision = -1;
242
243         ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
244         if (ret < 0) {
245                 if (ret != -EINTR)
246                         printk(KERN_ERR "omapdsp: configuration error!\n");
247                 ret = 1;
248                 goto out;
249         }
250
251 #if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
252         /*
253          * MBREV 3.2 or earlier doesn't assume DMA domain is on
254          * when DSPCFG command is sent
255          */
256         if ((mbox_revision == MBREV_3_0) ||
257             (mbox_revision == MBREV_3_2)) {
258                 if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
259                         goto out;
260         }
261 #endif
262
263         if ((ret = dsp_task_config_all(n_stask)) < 0)
264                 goto out;
265
266         /* initialization */
267 #ifdef CONFIG_OMAP_DSP_FBEXPORT
268         fbstat = FBSTAT_ENABLED;
269 #endif
270
271         /* send parameter */
272         ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
273         if (ret < 0)
274                 goto out;
275
276         /* create runtime sysfs entries */
277         ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
278         if (ret)
279                 printk(KERN_ERR "device_create_file failed: %d\n", ret);
280  out:
281         dsp_mem_disable((void *)dspmem_base);
282         return ret;
283 }
284
285 static int dsp_uncfg(void)
286 {
287         if (dsp_taskmod_busy()) {
288                 printk(KERN_WARNING "omapdsp: tasks are busy.\n");
289                 return -EBUSY;
290         }
291
292         /* FIXME: lock task module */
293
294         /* remove runtime sysfs entries */
295         device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
296
297         dsp_mbox_stop();
298         dsp_twch_stop();
299         dsp_mem_stop();
300         dsp_err_stop();
301         dsp_dbg_stop();
302         dsp_task_unconfig_all();
303         ipbuf_stop();
304
305         return 0;
306 }
307
308 static int dsp_suspend(void)
309 {
310         int ret;
311
312         ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
313         if (ret < 0) {
314                 if (ret != -EINVAL)
315                         printk(KERN_ERR "omapdsp: DSP suspend error!\n");
316                 return ret;
317         }
318
319         udelay(100);    /* wait for DSP-side execution */
320         return 0;
321 }
322
323 int dsp_cfgstat_request(enum cfgstat_e st_req)
324 {
325         static DEFINE_MUTEX(cfgstat_lock);
326         int ret = 0, ret_override = 0;
327
328         if (mutex_lock_interruptible(&cfgstat_lock))
329                 return -EINTR;
330
331 again:
332         switch (st_req) {
333
334         /* cfgstat takes CLEAN, READY or SUSPEND,
335            while st_req can take SUSPEND in addition. */
336
337         case CFGSTAT_CLEAN:
338                 if (cfgstat == CFGSTAT_CLEAN)
339                         goto up_out;
340                 if ((ret = dsp_uncfg()) < 0)
341                         goto up_out;
342                 break;
343
344         case CFGSTAT_READY:
345                 if (cfgstat != CFGSTAT_CLEAN) {
346                         printk(KERN_ERR "omapdsp: DSP is ready already!\n");
347                         ret = -EINVAL;
348                         goto up_out;
349                 }
350
351                 ret = dsp_cfg();
352                 if (ret > 0) {  /* failed, but state is clear. */
353                         ret = -EINVAL;
354                         goto up_out;
355                 } else if (ret < 0) {   /* failed, need cleanup. */
356                         st_req = CFGSTAT_CLEAN;
357                         ret_override = ret;
358                         goto again;
359                 }
360                 break;
361
362         /*
363          * suspend / resume
364          * DSP is not reset within this code, but done in omap_pm_suspend.
365          * so if these functions are called from sysfs,
366          * DSP should be reset / unreset out of these functions.
367          */
368         case CFGSTAT_SUSPEND:
369                 switch (cfgstat) {
370
371                 case CFGSTAT_CLEAN:
372                         if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
373                                 printk(KERN_WARNING
374                                        "omapdsp: illegal operation -- trying "
375                                        "suspend DSP while it is running but "
376                                        "not configured.\n"
377                                        "  Resetting DSP.\n");
378                                 dsp_cpustat_request(CPUSTAT_RESET);
379                                 ret = -EINVAL;
380                         }
381                         goto up_out;
382
383                 case CFGSTAT_READY:
384                         if ((ret = dsp_suspend()) < 0)
385                                 goto up_out;
386                         break;
387
388                 case CFGSTAT_SUSPEND:
389                         goto up_out;
390
391                 default:
392                         BUG();
393
394                 }
395
396                 break;
397
398         case CFGSTAT_RESUME:
399                 if (cfgstat != CFGSTAT_SUSPEND) {
400                         printk(KERN_WARNING
401                                "omapdsp: DSP resume request, but DSP is not in "
402                                "suspend state.\n");
403                         ret = -EINVAL;
404                         goto up_out;
405                 }
406                 st_req = CFGSTAT_READY;
407                 break;
408
409         default:
410                 BUG();
411
412         }
413
414         cfgstat = st_req;
415 up_out:
416         mutex_unlock(&cfgstat_lock);
417         return ret_override ? ret_override : ret;
418 }
419
420 enum cfgstat_e dsp_cfgstat_get_stat(void)
421 {
422         return cfgstat;
423 }
424
425 /*
426  * polls all tasks
427  */
428 static int dsp_poll(void)
429 {
430         int ret;
431
432         ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
433         if ((ret < 0) && (ret != -EINTR))
434                 printk(KERN_ERR "omapdsp: poll error!\n");
435
436         return ret;
437 }
438
439 int dsp_set_runlevel(u8 level)
440 {
441         if (level == RUNLEVEL_RECOVERY) {
442                 if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
443                         return -EINVAL;
444         } else {
445                 if ((level < RUNLEVEL_USER) ||
446                     (level > RUNLEVEL_SUPER))
447                         return -EINVAL;
448                 if (mbcompose_send(RUNLEVEL, level, 0) < 0)
449                         return -EINVAL;
450         }
451
452         return 0;
453 }
454
455 #ifdef CONFIG_OMAP_DSP_FBEXPORT
456 static void dsp_fbctl_enable(void)
457 {
458         mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
459 }
460
461 static int dsp_fbctl_disable(void)
462 {
463         int ret;
464
465         ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
466                                            NULL);
467         if ((ret < 0) && (ret != -EINTR))
468                 printk(KERN_ERR "omapdsp: fb disable error!\n");
469
470         return 0;
471 }
472
473 static int dsp_fbstat_request(enum fbstat_e st)
474 {
475         static DEFINE_MUTEX(fbstat_lock);
476         int ret = 0;
477
478         if (mutex_lock_interruptible(&fbstat_lock))
479                 return -EINTR;
480
481         if (st == fbstat)
482                 goto up_out;
483
484         switch (st) {
485         case FBSTAT_ENABLED:
486                 dsp_fbctl_enable();
487                 break;
488         case FBSTAT_DISABLED:
489                 if ((ret = dsp_fbctl_disable()) < 0)
490                         goto up_out;
491                 break;
492         default:
493                 BUG();
494         }
495
496         fbstat = st;
497 up_out:
498         mutex_unlock(&fbstat_lock);
499         return 0;
500 }
501 #endif /* CONFIG_OMAP_DSP_FBEXPORT */
502
503 /*
504  * DSP control device file operations
505  */
506 static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
507                          unsigned int cmd, unsigned long arg)
508 {
509         int ret = 0;
510
511         switch (cmd) {
512         /*
513          * command level 1: commands which don't need lock
514          */
515         case DSPCTL_IOCTL_RUN:
516                 dsp_cpustat_request(CPUSTAT_RUN);
517                 break;
518
519         case DSPCTL_IOCTL_RESET:
520                 dsp_cpustat_request(CPUSTAT_RESET);
521                 break;
522
523         case DSPCTL_IOCTL_SETRSTVECT:
524                 ret = dsp_set_rstvect((dsp_long_t)arg);
525                 break;
526
527 #ifdef CONFIG_ARCH_OMAP1
528         case DSPCTL_IOCTL_CPU_IDLE:
529                 dsp_cpustat_request(CPUSTAT_CPU_IDLE);
530                 break;
531
532         case DSPCTL_IOCTL_GBL_IDLE:
533                 dsp_cpustat_request(CPUSTAT_GBL_IDLE);
534                 break;
535
536         case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
537                 mpui_wordswap_on();
538                 break;
539
540         case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
541                 mpui_wordswap_off();
542                 break;
543
544         case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
545                 mpui_byteswap_on();
546                 break;
547
548         case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
549                 mpui_byteswap_off();
550                 break;
551 #endif /* CONFIG_ARCH_OMAP1 */
552
553         case DSPCTL_IOCTL_TASKCNT:
554                 ret = dsp_task_count();
555                 break;
556
557         case DSPCTL_IOCTL_MBSEND:
558                 {
559                         struct omap_dsp_mailbox_cmd u_cmd;
560                         mbox_msg_t msg;
561                         if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
562                                 return -EFAULT;
563                         msg = (u_cmd.cmd << 16) | u_cmd.data;
564                         ret = dsp_mbcmd_send((struct mbcmd *)&msg);
565                         break;
566                 }
567
568         case DSPCTL_IOCTL_SETVAR:
569                 {
570                         struct omap_dsp_varinfo var;
571                         if (copy_from_user(&var, (void *)arg, sizeof(var)))
572                                 return -EFAULT;
573                         ret = dsp_setvar(var.varid, var.val[0]);
574                         break;
575                 }
576
577         case DSPCTL_IOCTL_RUNLEVEL:
578                 ret = dsp_set_runlevel(arg);
579                 break;
580
581 #ifdef CONFIG_OMAP_DSP_FBEXPORT
582         case DSPCTL_IOCTL_FBEN:
583                 ret = dsp_fbstat_request(FBSTAT_ENABLED);
584                 break;
585 #endif
586
587         /*
588          * command level 2: commands which need lock
589          */
590         case DSPCTL_IOCTL_DSPCFG:
591                 ret = dsp_cfgstat_request(CFGSTAT_READY);
592                 break;
593
594         case DSPCTL_IOCTL_DSPUNCFG:
595                 ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
596                 break;
597
598         case DSPCTL_IOCTL_POLL:
599                 ret = dsp_poll();
600                 break;
601
602 #ifdef CONFIG_OMAP_DSP_FBEXPORT
603         case DSPCTL_IOCTL_FBDIS:
604                 ret = dsp_fbstat_request(FBSTAT_DISABLED);
605                 break;
606 #endif
607
608         case DSPCTL_IOCTL_SUSPEND:
609                 if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
610                         break;
611                 dsp_cpustat_request(CPUSTAT_RESET);
612                 break;
613
614         case DSPCTL_IOCTL_RESUME:
615                 if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
616                         break;
617                 dsp_cpustat_request(CPUSTAT_RUN);
618                 break;
619
620         case DSPCTL_IOCTL_REGMEMR:
621                 {
622                         struct omap_dsp_reginfo *u_reg = (void *)arg;
623                         u16 adr, val;
624
625                         if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
626                                 return -EFAULT;
627                         if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
628                                 return ret;
629                         if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
630                                 return -EFAULT;
631                         break;
632                 }
633
634         case DSPCTL_IOCTL_REGMEMW:
635                 {
636                         struct omap_dsp_reginfo reg;
637
638                         if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
639                                 return -EFAULT;
640                         ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
641                         break;
642                 }
643
644         case DSPCTL_IOCTL_REGIOR:
645                 {
646                         struct omap_dsp_reginfo *u_reg = (void *)arg;
647                         u16 adr, val;
648
649                         if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
650                                 return -EFAULT;
651                         if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
652                                 return ret;
653                         if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
654                                 return -EFAULT;
655                         break;
656                 }
657
658         case DSPCTL_IOCTL_REGIOW:
659                 {
660                         struct omap_dsp_reginfo reg;
661
662                         if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
663                                 return -EFAULT;
664                         ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
665                         break;
666                 }
667
668         case DSPCTL_IOCTL_GETVAR:
669                 {
670                         struct omap_dsp_varinfo *u_var = (void *)arg;
671                         u8 varid;
672                         u16 val[5]; /* maximum */
673                         int argc;
674
675                         if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
676                                 return -EFAULT;
677                         switch (varid) {
678                         case VARID_ICRMASK:
679                                 argc = 1;
680                                 break;
681                         case VARID_LOADINFO:
682                                 argc = 5;
683                                 break;
684                         default:
685                                 return -EINVAL;
686                         }
687                         if ((ret = dsp_getvar(varid, val)) < 0)
688                                 return ret;
689                         if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
690                                 return -EFAULT;
691                         break;
692                 }
693
694         default:
695                 return -ENOIOCTLCMD;
696         }
697
698         return ret;
699 }
700
701 /*
702  * functions called from mailbox interrupt routine
703  */
704 void mbox_suspend(struct mbcmd *mb)
705 {
706         misc_mbcmd_response(mb, 0, 0);
707 }
708
709 void mbox_dspcfg(struct mbcmd *mb)
710 {
711         u8 last   = mb->cmd_l & 0x80;
712         u8 cfgcmd = mb->cmd_l & 0x7f;
713         static dsp_long_t tmp_ipb_adr;
714
715         if (!waitqueue_active(&misc_mb_wait.wait_q) ||
716             (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
717                 printk(KERN_WARNING
718                        "mbox: DSPCFG command received, "
719                        "but nobody is waiting for it...\n");
720                 return;
721         }
722
723         /* mailbox protocol check */
724         if (cfgcmd == DSPCFG_PROTREV) {
725                 mbox_revision = mb->data;
726                 if (mbox_revision == MBPROT_REVISION)
727                         return;
728 #ifdef OLD_BINARY_SUPPORT
729                 else if ((mbox_revision == MBREV_3_0) ||
730                          (mbox_revision == MBREV_3_2)) {
731                         printk(KERN_WARNING
732                                "mbox: ***** old DSP binary *****\n"
733                                "  Please update your DSP application.\n");
734                         return;
735                 }
736 #endif
737                 else {
738                         printk(KERN_ERR
739                                "mbox: protocol revision check error!\n"
740                                "  expected=0x%04x, received=0x%04x\n",
741                                MBPROT_REVISION, mb->data);
742                         mbox_revision = -1;
743                         goto abort1;
744                 }
745         }
746
747         /*
748          * following commands are accepted only after
749          * revision check has been passed.
750          */
751         if (!mbox_revision < 0) {
752                 pr_info("mbox: DSPCFG command received, "
753                         "but revision check has not been passed.\n");
754                 return;
755         }
756
757         switch (cfgcmd) {
758         case DSPCFG_SYSADRH:
759                 tmp_ipb_adr = (u32)mb->data << 16;
760                 break;
761
762         case DSPCFG_SYSADRL:
763                 tmp_ipb_adr |= mb->data;
764                 break;
765
766         case DSPCFG_ABORT:
767                 goto abort1;
768
769         default:
770                 printk(KERN_ERR
771                        "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
772                        mb->cmd_l, mb->data);
773                 return;
774         }
775
776         if (last) {
777                 void *badr;
778                 u16 bln;
779                 u16 bsz;
780                 volatile u16 *buf;
781                 void *ipb_sys_da, *ipb_sys_ad;
782                 void *mbseq;     /* FIXME: 3.4 obsolete */
783                 short *dbg_buf;
784                 u16 dbg_buf_sz, dbg_line_sz;
785                 struct mem_sync_struct mem_sync, *mem_syncp;
786
787                 ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
788                 if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
789                         goto abort1;
790
791                 if (dsp_mem_enable(ipbuf_sys_da) < 0) {
792                         printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
793                         goto abort1;
794                 }
795                 if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
796                         printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
797                         dsp_mem_disable(ipbuf_sys_da);
798                         goto abort1;
799                 }
800                 /*
801                  * read configuration data on system IPBUF
802                  * we must read with 16bit-access
803                  */
804 #ifdef OLD_BINARY_SUPPORT
805                 if (mbox_revision == MBPROT_REVISION) {
806 #endif
807                         buf = ipbuf_sys_da->d;
808                         n_stask        = buf[0];
809                         bln            = buf[1];
810                         bsz            = buf[2];
811                         badr           = MKVIRT(buf[3], buf[4]);
812                         /* ipb_sys_da     = MKVIRT(buf[5], buf[6]); */
813                         ipb_sys_ad     = MKVIRT(buf[7], buf[8]);
814                         mbseq          = MKVIRT(buf[9], buf[10]);
815                         dbg_buf        = MKVIRT(buf[11], buf[12]);
816                         dbg_buf_sz     = buf[13];
817                         dbg_line_sz    = buf[14];
818                         mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
819                         mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
820                         mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
821                         mem_syncp = &mem_sync;
822 #ifdef OLD_BINARY_SUPPORT
823                 } else if (mbox_revision == MBREV_3_2) {
824                         buf = ipbuf_sys_da->d;
825                         n_stask     = buf[0];
826                         bln         = buf[1];
827                         bsz         = buf[2];
828                         badr        = MKVIRT(buf[3], buf[4]);
829                         /* ipb_sys_da  = MKVIRT(buf[5], buf[6]); */
830                         ipb_sys_ad  = MKVIRT(buf[7], buf[8]);
831                         mbseq       = MKVIRT(buf[9], buf[10]);
832                         dbg_buf     = NULL;
833                         dbg_buf_sz  = 0;
834                         dbg_line_sz = 0;
835                         mem_syncp   = NULL;
836                 } else if (mbox_revision == MBREV_3_0) {
837                         buf = ipbuf_sys_da->d;
838                         n_stask     = buf[0];
839                         bln         = buf[1];
840                         bsz         = buf[2];
841                         badr        = MKVIRT(buf[3], buf[4]);
842                         /* bkeep       = buf[5]; */
843                         /* ipb_sys_da  = MKVIRT(buf[6], buf[7]); */
844                         ipb_sys_ad  = MKVIRT(buf[8], buf[9]);
845                         mbseq       = MKVIRT(buf[10], buf[11]);
846                         dbg_buf     = NULL;
847                         dbg_buf_sz  = 0;
848                         dbg_line_sz = 0;
849                         mem_syncp   = NULL;
850                 } else { /* should not occur */
851                         dsp_mem_disable(ipbuf_sys_da);
852                         goto abort1;
853                 }
854 #endif /* OLD_BINARY_SUPPORT */
855
856                 release_ipbuf_pvt(ipbuf_sys_da);
857                 dsp_mem_disable(ipbuf_sys_da);
858
859                 /*
860                  * following configurations need to be done before
861                  * waking up the dspcfg initiator process.
862                  */
863                 if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
864                         goto abort1;
865                 if (ipbuf_config(bln, bsz, badr) < 0)
866                         goto abort1;
867                 if (dsp_mbox_config(mbseq) < 0)
868                         goto abort2;
869                 if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
870                         goto abort2;
871                 if (dsp_mem_sync_config(mem_syncp) < 0)
872                         goto abort2;
873
874                 misc_mb_wait.cmd_h = 0;
875                 wake_up_interruptible(&misc_mb_wait.wait_q);
876         }
877         return;
878
879 abort2:
880         ipbuf_stop();
881 abort1:
882         wake_up_interruptible(&misc_mb_wait.wait_q);
883         return;
884 }
885
886 void mbox_poll(struct mbcmd *mb)
887 {
888         misc_mbcmd_response(mb, 0, 0);
889 }
890
891 void mbox_regrw(struct mbcmd *mb)
892 {
893         switch (mb->cmd_l) {
894         case REGRW_DATA:
895                 misc_mbcmd_response(mb, 1, 0);
896                 break;
897         default:
898                 printk(KERN_ERR
899                        "mbox: Illegal REGRW command: "
900                        "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
901                 return;
902         }
903 }
904
905 void mbox_getvar(struct mbcmd *mb)
906 {
907         switch (mb->cmd_l) {
908         case VARID_ICRMASK:
909                 misc_mbcmd_response(mb, 1, 1);
910                 break;
911         case VARID_LOADINFO:
912                 misc_mbcmd_response(mb, 5, 1);
913                 break;
914         default:
915                 printk(KERN_ERR
916                        "mbox: Illegal GETVAR command: "
917                        "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
918                 return;
919         }
920 }
921
922 void mbox_fbctl_disable(struct mbcmd *mb)
923 {
924         misc_mbcmd_response(mb, 0, 0);
925 }
926
927 struct file_operations dsp_ctl_fops = {
928         .owner   = THIS_MODULE,
929         .ioctl   = dsp_ctl_ioctl,
930 };
931
932 /*
933  * sysfs files
934  */
935
936 /* ifver */
937 static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
938                           char *buf)
939 {
940         int len = 0;
941
942         /*
943          * I/F VERSION descriptions:
944          *
945          * 3.2: sysfs / udev support
946          *      KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
947          * 3.3: added following ioctls
948          *      DSPCTL_IOCTL_GBL_IDLE
949          *      DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
950          *      DSPCTL_IOCTL_POLL
951          */
952
953         /*
954          * print all supporting I/F VERSIONs, like followings.
955          *
956          * len += sprintf(buf, "3.2\n");
957          * len += sprintf(buf, "3.3\n");
958          */
959         len += sprintf(buf + len, "3.2\n");
960         len += sprintf(buf + len, "3.3\n");
961
962         return len;
963 }
964
965 /* cpustat */
966 static char *cpustat_name[CPUSTAT_MAX] = {
967         [CPUSTAT_RESET]    = "reset",
968 #ifdef CONFIG_ARCH_OMAP1
969         [CPUSTAT_GBL_IDLE] = "gbl_idle",
970         [CPUSTAT_CPU_IDLE] = "cpu_idle",
971 #endif
972         [CPUSTAT_RUN]      = "run",
973 };
974
975 static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
976                             char *buf)
977 {
978         return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
979 }
980
981 /* icrmask */
982 static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
983                             char *buf)
984 {
985         return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
986 }
987
988 static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
989                              const char *buf, size_t count)
990 {
991         u16 mask;
992         int ret;
993
994         mask = simple_strtol(buf, NULL, 16);
995         dsp_cpustat_set_icrmask(mask);
996
997         if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
998                 ret = dsp_setvar(VARID_ICRMASK, mask);
999                 if (ret < 0)
1000                         return ret;
1001         }
1002
1003         return count;
1004 }
1005
1006 /* loadinfo */
1007 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
1008                              char *buf)
1009 {
1010         int len;
1011         int ret;
1012         u16 val[5];
1013
1014         if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
1015                 return ret;
1016
1017         /*
1018          * load info value range is 0(free) - 10000(busy):
1019          * if CPU load is not measured on DSP, it sets 0xffff at val[0].
1020          */
1021
1022         if (val[0] == 0xffff) {
1023                 len = sprintf(buf,
1024                               "currently DSP load info is not available.\n");
1025                 goto out;
1026         }
1027
1028         len = sprintf(buf,
1029                       "DSP load info:\n"
1030                       "  10ms average = %3d.%02d%%\n"
1031                       "  1sec average = %3d.%02d%%  busiest 10ms = %3d.%02d%%\n"
1032                       "  1min average = %3d.%02d%%  busiest 1s   = %3d.%02d%%\n",
1033                       val[0]/100, val[0]%100,
1034                       val[1]/100, val[1]%100, val[2]/100, val[2]%100,
1035                       val[3]/100, val[3]%100, val[4]/100, val[4]%100);
1036 out:
1037         return len;
1038 }
1039
1040 int __init dsp_ctl_init(void)
1041 {
1042         int ret;
1043
1044         ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
1045         if (unlikely(ret))
1046                 return ret;
1047         ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
1048         if (unlikely(ret))
1049                 goto fail_create_cpustat;
1050         ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
1051         if (unlikely(ret))
1052                 goto fail_create_icrmask;
1053
1054         return 0;
1055
1056 fail_create_icrmask:
1057         device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
1058 fail_create_cpustat:
1059         device_remove_file(omap_dsp->dev, &dev_attr_ifver);
1060
1061         return ret;
1062 }
1063
1064 void dsp_ctl_exit(void)
1065 {
1066         device_remove_file(omap_dsp->dev, &dev_attr_ifver);
1067         device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
1068         device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
1069 }