This is DSP Gateway v3.3 patch.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/01/21: DSP Gateway version 3.2
+ * 2005/06/09: DSP Gateway version 3.3
*/
#include "hardware_dsp.h"
#ifdef OLD_BINARY_SUPPORT
#define MBREV_3_0 0x0017
+#define MBREV_3_2 0x0018
#endif
#define DSP_INIT_PAGE 0xfff000
#define IDLEPG_BASE 0xfffe00
#define IDLEPG_SIZE 0x100
+/* timeout value for DSP response */
+#define DSP_TIMEOUT (10 * HZ)
+
+enum dsp_mem_type_e {
+ MEM_TYPE_CROSSING = -1,
+ MEM_TYPE_NONE = 0,
+ MEM_TYPE_DARAM,
+ MEM_TYPE_SARAM,
+ MEM_TYPE_EXTERN,
+};
+
+enum arm_dsp_dir {
+ DIR_A2D,
+ DIR_D2A,
+};
+
/*
* INT_D2A_MB value definition
* INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox
#define TASKDEV_MAX 254
#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
#define MBCMD(nm) OMAP_DSP_MBCMD_##nm
+struct sync_seq {
+ unsigned short da_dsp;
+ unsigned short da_arm;
+ unsigned short ad_dsp;
+ unsigned short ad_arm;
+};
+
+struct mem_sync_struct {
+ struct sync_seq *DARAM;
+ struct sync_seq *SARAM;
+ struct sync_seq *SDRAM;
+};
+
/* struct mbcmd and struct mbcmd_hw must be compatible */
struct mbcmd {
unsigned short cmd_l:8;
extern void dsp_mb_start(void);
extern void dsp_mb_stop(void);
-extern void dsp_mb_config(void *sync_seq_adr);
+extern int dsp_mb_config(void *p);
extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid,
int try_cnt);
-extern int __mbsend(struct mbcmd *mb);
-extern int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg,
- int recovery_flag);
-#define dsp_mbsend(mb) __dsp_mbsend(mb, NULL, 0)
-#define dsp_mbsend_recovery(mb) __dsp_mbsend(mb, NULL, 1)
-#define dsp_mbsend_exarg(mb, arg) __dsp_mbsend(mb, arg, 0)
-extern int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
- wait_queue_head_t *q);
-#define dsp_mbsend_and_wait(mb, q) \
- __dsp_mbsend_and_wait(mb, NULL, q)
-#define dsp_mbsend_and_wait_exarg(mb, arg, q) \
- __dsp_mbsend_and_wait(mb, arg, q)
+extern int __mbcmd_send(struct mbcmd *mb);
+extern int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag);
+#define dsp_mbcmd_send(mb) __dsp_mbcmd_send(mb, NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send(mb, arg, 0)
+extern int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q);
+#define dsp_mbcmd_send_and_wait(mb, q) \
+ __dsp_mbcmd_send_and_wait(mb, NULL, q)
+#define dsp_mbcmd_send_and_wait_exarg(mb, arg, q) \
+ __dsp_mbcmd_send_and_wait(mb, arg, q)
+int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
+ int recovery_flag);
+#define dsp_mbsend(cmdh, cmdl, data) \
+ __dsp_mbsend(cmdh, cmdl, data, 0)
+#define dsp_mbsend_recovery(cmdh, cmdl, data) \
+ __dsp_mbsend(cmdh, cmdl, data, 1)
extern void ipbuf_start(void);
extern void ipbuf_stop(void);
-extern int ipbuf_config(unsigned short ln, unsigned short lsz,
- unsigned long adr);
+extern int ipbuf_config(unsigned short ln, unsigned short lsz, void *base);
+extern int ipbuf_sys_config(void *p, enum arm_dsp_dir dir);
+extern int ipbuf_p_validate(void *p, enum arm_dsp_dir dir);
extern unsigned short get_free_ipbuf(unsigned char tid);
extern void unuse_ipbuf_nowait(unsigned short bid);
extern void unuse_ipbuf(unsigned short bid);
(ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \
} while(0)
+extern int mbx_revision;
+
extern int dsp_is_ready(void);
extern int dspuncfg(void);
extern void dsp_runlevel(unsigned char level);
extern int dsp_tadd(unsigned char minor, unsigned long adr);
extern int dsp_tdel(unsigned char minor);
extern int dsp_tkill(unsigned char minor);
-extern long taskdev_state(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz);
+extern void dsp_dbg_stop(void);
extern int ipbuf_is_held(unsigned char tid, unsigned short bid);
+extern void dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
extern int dsp_mem_enable(void *adr);
-extern int dsp_mem_disable(void *adr);
-extern int __dsp_mem_enable(void *adr);
-extern int __dsp_mem_disable(void *adr);
+extern void dsp_mem_disable(void *adr);
+extern void dsp_mem_usecount_clear(void);
+extern void exmap_use(void *vadr, size_t len);
+extern void exmap_unuse(void *vadr, size_t len);
extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
extern void dsp_mem_start(void);
+extern void dsp_mem_stop(void);
extern void dsp_twch_start(void);
extern void dsp_twch_stop(void);
#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
extern char *subcmd_name(struct mbcmd *mb);
-enum mblog_dir {
- MBLOG_DIR_AD,
- MBLOG_DIR_DA,
-};
-
-extern void mblog_add(struct mbcmd *mb, enum mblog_dir dir);
+extern void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir);
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
-extern void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir);
+extern void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir);
#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
#define mblog_printcmd(mb, dir) do {} while(0)
#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/11/19: DSP Gateway version 3.2
+ * 2005/06/13: DSP Gateway version 3.3
*/
#include <linux/module.h>
struct clk *dsp_ck_handle;
struct clk *api_ck_handle;
-unsigned long dspmem_base, dspmem_size;
-int dsp_runstat = RUNSTAT_RESET;
-unsigned short dsp_icrmask = DSPREG_ICR_EMIF_IDLE_DOMAIN |
- DSPREG_ICR_DPLL_IDLE_DOMAIN |
- DSPREG_ICR_PER_IDLE_DOMAIN |
- DSPREG_ICR_CACHE_IDLE_DOMAIN |
- DSPREG_ICR_DMA_IDLE_DOMAIN |
- DSPREG_ICR_CPU_IDLE_DOMAIN;
+unsigned long dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+struct cpustat {
+ struct semaphore sem;
+ enum e_cpustat stat;
+ enum e_cpustat req;
+ unsigned short icrmask;
+ struct {
+ int mpui;
+ int mem;
+ int mem_delayed;
+ } usecount;
+ int (*mem_req_cb)(void);
+ void (*mem_rel_cb)(void);
+};
+struct cpustat cpustat = {
+ .sem = __MUTEX_INITIALIZER(cpustat.sem),
+ .stat = CPUSTAT_RESET,
+ .icrmask = 0xffff,
+};
int dsp_set_rstvect(unsigned long adr)
{
}
/* program size must be multiple of 2 */
-#define IDLE_TEXT_SIZE 28
-#define IDLE_TEXT(icr) { \
+#define GBL_IDLE_TEXT_SIZE 52
+#define GBL_IDLE_TEXT_INIT { \
+ /* SAM */ \
+ 0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \
+ 0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \
/* disable WDT */ \
- 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: mov AR3 0x3404 */ \
- 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: mov *AR3 0x00f5 */ \
- 0x9a, /* 0x9a: port */ \
- 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: mov *AR3 0x00a0 */ \
- 0x9a, /* 0x9a: port */ \
+ 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
+ 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* *IER0 = 0, *IER1 = 0 */ \
+ 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ /* *ICR = 0xffff */ \
+ 0x3c, 0x1b, /* 0x3c1b: MOV 0x1, AR3 */ \
+ 0xfb, 0x61, 0xff, 0xff, /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* HOM */ \
+ 0xf5, 0x41, 0x03, 0x00, /* 0xf5410300: OR 0x0300, *AR2 */ \
+ /* idle and loop forever */ \
+ 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
+ 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
+ 0x20, 0x20, 0x20, /* 0x20: NOP */ \
+}
+
+/* program size must be multiple of 2 */
+#define CPU_IDLE_TEXT_SIZE 48
+#define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
+ /* SAM */ \
+ 0x3c, 0x4b, /* 0x3c4b: MOV 0x4, AR3 */ \
+ 0xf4, 0x61, 0xfc, 0xff, /* 0xf461fcff: AND 0xfcff, *AR3 */ \
+ /* disable WDT */ \
+ 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
+ 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+ 0x9a, /* 0x9a: PORT */ \
+ /* *IER0 = 0, *IER1 = 0 */ \
+ 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
+ 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
+ 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
/* set ICR = icr */ \
- 0x3c, 0x1b, /* 0x3c1b: mov AR3 0x1 */ \
- 0xe6, 0x61, (icr), /* 0xe661**: mov *AR3, icr */ \
- 0x9a, /* 0x9a: port */ \
+ 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \
+ 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \
+ 0x9a, /* 0x9a: PORT */ \
/* idle and loop forever */ \
- 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: idle */ \
- 0x4a, 0x7a, /* 0x4a7a: b -6 (infinite loop) */ \
- 0x20, 0x20 /* 0x20: nop */ \
+ 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
+ 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
+ 0x20, 0x20, 0x20 /* 0x20: nop */ \
}
/*
*/
static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI;
-void dsp_idle(void)
+static void dsp_gbl_idle(void)
+{
+ unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
+
+ __dsp_reset();
+ clk_use(api_ck_handle);
+
+#if 0
+ omap_writew(MPUI_DSP_BOOT_CONFIG_IDLE, MPUI_DSP_BOOT_CONFIG);
+#endif
+ simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+ GBL_IDLE_TEXT_SIZE);
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
+ else
+ dsp_set_rstvect(idle_boot_base);
+
+ __dsp_run();
+ udelay(100); /* to make things stable */
+ clk_unuse(api_ck_handle);
+}
+
+static void dsp_cpu_idle(void)
{
- unsigned char icr;
+ unsigned short icr_tmp;
+ unsigned char icrh, icrl;
- disable_irq(INT_DSP_MMU);
- preempt_disable();
__dsp_reset();
clk_use(api_ck_handle);
/*
* icr settings:
* DMA should not sleep for DARAM/SARAM access
- * DPLL should not sleep for DMA.
+ * DPLL should not sleep while any other domain is active
*/
- icr = dsp_icrmask &
- ~(DSPREG_ICR_DMA_IDLE_DOMAIN | DSPREG_ICR_DPLL_IDLE_DOMAIN) &
- 0xff;
+ icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA_IDLE_DOMAIN |
+ DSPREG_ICR_DPLL_IDLE_DOMAIN);
+ icrh = icr_tmp >> 8;
+ icrl = icr_tmp & 0xff;
{
- unsigned char idle_text[IDLE_TEXT_SIZE] = IDLE_TEXT(icr);
+ unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
- IDLE_TEXT_SIZE);
+ CPU_IDLE_TEXT_SIZE);
}
if (idle_boot_base == DSP_BOOT_ADR_MPUI)
omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
else
dsp_set_rstvect(idle_boot_base);
- clk_unuse(api_ck_handle);
- udelay(10); /* to make things stable */
__dsp_run();
- dsp_runstat = RUNSTAT_IDLE;
- preempt_enable();
- enable_irq(INT_DSP_MMU);
+ udelay(100); /* to make things stable */
+ clk_unuse(api_ck_handle);
}
void dsp_set_idle_boot_base(unsigned long adr, size_t size)
if (adr == idle_boot_base)
return;
idle_boot_base = adr;
- if (size < IDLE_TEXT_SIZE) {
+ if ((size < GBL_IDLE_TEXT_SIZE) ||
+ (size < CPU_IDLE_TEXT_SIZE)) {
printk(KERN_ERR
"omapdsp: size for idle program is not enough!\n");
BUG();
}
- if (dsp_runstat == RUNSTAT_IDLE)
- dsp_idle();
+
+ /* restart idle program with new base address */
+ if (cpustat.stat == CPUSTAT_GBL_IDLE)
+ dsp_gbl_idle();
+ if (cpustat.stat == CPUSTAT_CPU_IDLE)
+ dsp_cpu_idle();
}
static unsigned short save_dsp_idlect2;
omap_writew(save_arm_idlect2, ARM_IDLECT2);
/* Run DSP, if it was running */
- if (dsp_runstat != RUNSTAT_RESET)
+ if (cpustat.stat != CPUSTAT_RESET)
__dsp_run();
}
+
static int init_done;
static int __init omap_dsp_init(void)
if (cpu_is_omap1510()) {
dspmem_base = OMAP1510_DSP_BASE;
dspmem_size = OMAP1510_DSP_SIZE;
+ daram_base = OMAP1510_DARAM_BASE;
+ daram_size = OMAP1510_DARAM_SIZE;
+ saram_base = OMAP1510_SARAM_BASE;
+ saram_size = OMAP1510_SARAM_SIZE;
}
#endif
#ifdef CONFIG_ARCH_OMAP16XX
if (cpu_is_omap16xx()) {
dspmem_base = OMAP16XX_DSP_BASE;
dspmem_size = OMAP16XX_DSP_SIZE;
+ daram_base = OMAP16XX_DARAM_BASE;
+ daram_size = OMAP16XX_DARAM_SIZE;
+ saram_base = OMAP16XX_SARAM_BASE;
+ saram_size = OMAP16XX_SARAM_SIZE;
}
#endif
if (dspmem_size == 0) {
return 0;
}
-void omap_dsp_request_idle(void)
+static void dsp_cpustat_update(void)
{
- if (dsp_runstat == RUNSTAT_RESET) {
- if (!init_done)
- omap_dsp_init();
- dsp_idle();
+ if (!init_done)
+ omap_dsp_init();
+
+ if (cpustat.req == CPUSTAT_RUN) {
+ if (cpustat.stat < CPUSTAT_RUN) {
+ __dsp_reset();
+ clk_use(api_ck_handle);
+ udelay(10);
+ __dsp_run();
+ cpustat.stat = CPUSTAT_RUN;
+ enable_irq(INT_DSP_MMU);
+ }
+ return;
+ }
+
+ /* cpustat.stat < CPUSTAT_RUN */
+
+ if (cpustat.stat == CPUSTAT_RUN) {
+ disable_irq(INT_DSP_MMU);
+ clk_unuse(api_ck_handle);
+ }
+
+ /*
+ * (1) when ARM wants DARAM access, MPUI should be SAM and
+ * DSP needs to be on.
+ * (2) if any bits of icr is masked, we can not enter global idle.
+ */
+ if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
+ (cpustat.usecount.mem > 0) ||
+ (cpustat.usecount.mem_delayed > 0) ||
+ ((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
+ if (cpustat.stat != CPUSTAT_CPU_IDLE) {
+ dsp_cpu_idle();
+ cpustat.stat = CPUSTAT_CPU_IDLE;
+ }
+ return;
+ }
+
+ /*
+ * when ARM only needs MPUI access, MPUI can be HOM and
+ * DSP can be idling.
+ */
+ if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
+ (cpustat.usecount.mpui > 0)) {
+ if (cpustat.stat != CPUSTAT_GBL_IDLE) {
+ dsp_gbl_idle();
+ cpustat.stat = CPUSTAT_GBL_IDLE;
+ }
+ return;
+ }
+
+ /*
+ * no user, no request
+ */
+ if (cpustat.stat != CPUSTAT_RESET) {
+ __dsp_reset();
+ cpustat.stat = CPUSTAT_RESET;
}
}
+void dsp_cpustat_request(enum e_cpustat req)
+{
+ down(&cpustat.sem);
+ cpustat.req = req;
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+enum e_cpustat dsp_cpustat_get_stat(void)
+{
+ return cpustat.stat;
+}
+
+unsigned short dsp_cpustat_get_icrmask(void)
+{
+ return cpustat.icrmask;
+}
+
+void dsp_cpustat_set_icrmask(unsigned short mask)
+{
+ down(&cpustat.sem);
+ cpustat.icrmask = mask;
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+void omap_dsp_request_mpui(void)
+{
+ down(&cpustat.sem);
+ if (cpustat.usecount.mpui++ == 0)
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+void omap_dsp_release_mpui(void)
+{
+ down(&cpustat.sem);
+ if (cpustat.usecount.mpui-- == 0) {
+ printk(KERN_ERR
+ "omapdsp: unbalanced mpui request/release detected.\n"
+ " cpustat.usecount.mpui is going to be "
+ "less than zero! ... fixed to be zero.\n");
+ cpustat.usecount.mpui = 0;
+ }
+ if (cpustat.usecount.mpui == 0)
+ dsp_cpustat_update();
+ up(&cpustat.sem);
+}
+
+int omap_dsp_request_mem(void)
+{
+ int ret = 0;
+
+ down(&cpustat.sem);
+ if ((cpustat.usecount.mem++ == 0) &&
+ (cpustat.usecount.mem_delayed == 0)) {
+ if (cpustat.mem_req_cb) {
+ if ((ret = cpustat.mem_req_cb()) < 0) {
+ cpustat.usecount.mem--;
+ goto out;
+ }
+ }
+ dsp_cpustat_update();
+ }
+out:
+ up(&cpustat.sem);
+
+ return ret;
+}
+
+/*
+ * release_mem will be delayed.
+ */
+static void do_release_mem(void) {
+ down(&cpustat.sem);
+ cpustat.usecount.mem_delayed = 0;
+ if (cpustat.usecount.mem == 0) {
+ dsp_cpustat_update();
+ if (cpustat.mem_rel_cb)
+ cpustat.mem_rel_cb();
+ }
+ up(&cpustat.sem);
+}
+
+static DECLARE_WORK(mem_rel_work, (void (*)(void *))do_release_mem, NULL);
+
+int omap_dsp_release_mem(void)
+{
+ down(&cpustat.sem);
+
+ /* cancel previous release work */
+ cancel_delayed_work(&mem_rel_work);
+ cpustat.usecount.mem_delayed = 0;
+
+ if (cpustat.usecount.mem-- == 0) {
+ printk(KERN_ERR
+ "omapdsp: unbalanced memory request/release detected.\n"
+ " cpustat.usecount.mem is going to be "
+ "less than zero! ... fixed to be zero.\n");
+ cpustat.usecount.mem = 0;
+ }
+ if (cpustat.usecount.mem == 0) {
+ cpustat.usecount.mem_delayed = 1;
+ schedule_delayed_work(&mem_rel_work, HZ);
+ }
+
+ up(&cpustat.sem);
+
+ return 0;
+}
+
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
+{
+ down(&cpustat.sem);
+
+ cpustat.mem_req_cb = req_cb;
+ cpustat.mem_rel_cb = rel_cb;
+
+ /*
+ * This function must be called while mem is enabled!
+ */
+ BUG_ON(cpustat.usecount.mem == 0);
+
+ up(&cpustat.sem);
+}
+
+void dsp_unregister_mem_cb(void)
+{
+ down(&cpustat.sem);
+ cpustat.mem_req_cb = NULL;
+ cpustat.mem_rel_cb = NULL;
+ up(&cpustat.sem);
+}
+
arch_initcall(omap_dsp_init);
EXPORT_SYMBOL(omap_dsp_pm_suspend);
EXPORT_SYMBOL(omap_dsp_pm_resume);
-EXPORT_SYMBOL(omap_dsp_request_idle);
+EXPORT_SYMBOL(omap_dsp_request_mpui);
+EXPORT_SYMBOL(omap_dsp_release_mpui);
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
#ifdef CONFIG_OMAP_DSP_MODULE
EXPORT_SYMBOL(dsp_ck_handle);
EXPORT_SYMBOL(api_ck_handle);
EXPORT_SYMBOL(dspmem_base);
EXPORT_SYMBOL(dspmem_size);
-EXPORT_SYMBOL(dsp_runstat);
-EXPORT_SYMBOL(dsp_icrmask);
+EXPORT_SYMBOL(daram_base);
+EXPORT_SYMBOL(daram_size);
+EXPORT_SYMBOL(saram_base);
+EXPORT_SYMBOL(saram_size);
EXPORT_SYMBOL(dsp_set_rstvect);
-EXPORT_SYMBOL(dsp_idle);
EXPORT_SYMBOL(dsp_set_idle_boot_base);
+EXPORT_SYMBOL(dsp_cpustat_request);
+EXPORT_SYMBOL(dsp_cpustat_get_stat);
+EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
+EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
+EXPORT_SYMBOL(dsp_register_mem_cb);
+EXPORT_SYMBOL(dsp_unregister_mem_cb);
EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
#endif
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/11/16: DSP Gateway version 3.2
+ * 2005/06/13: DSP Gateway version 3.3
*/
#include "hardware_dsp.h"
* default setting: wordswap = all, byteswap = APIMEM only
*/
#define mpui_wordswap_on() \
- { \
+ do { \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \
} while(0)
#define mpui_wordswap_off() \
- { \
+ do { \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \
} while(0)
#define mpui_byteswap_on() \
- { \
+ do { \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \
} while(0)
#define mpui_byteswap_off() \
- { \
+ do { \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \
* TC wordswap on / off
*/
#define tc_wordswap() \
- { \
+ do { \
omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
TC_ENDIANISM); \
} while(0)
#define tc_noswap() \
- { \
+ do { \
omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \
TC_ENDIANISM); \
} while(0)
#define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
#define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
-#define RUNSTAT_RESET 0
-#define RUNSTAT_IDLE 1
-#define RUNSTAT_RUN 2
-
extern struct clk *dsp_ck_handle;
extern struct clk *api_ck_handle;
-extern unsigned long dspmem_base, dspmem_size;
-extern int dsp_runstat;
-extern unsigned short dsp_icrmask;
+extern unsigned long dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+enum e_cpustat {
+ CPUSTAT_RESET = 0,
+ CPUSTAT_GBL_IDLE = 1,
+ CPUSTAT_CPU_IDLE = 2,
+ CPUSTAT_RUN = 3
+};
+
+#define cpustat_name(stat) \
+ ((stat == CPUSTAT_RESET) ? "RESET" :\
+ (stat == CPUSTAT_GBL_IDLE) ? "GBL_IDLE" :\
+ (stat == CPUSTAT_CPU_IDLE) ? "CPU_IDLE" :\
+ (stat == CPUSTAT_RUN) ? "RUN" :\
+ "unknown")
int dsp_set_rstvect(unsigned long adr);
-void dsp_idle(void);
void dsp_set_idle_boot_base(unsigned long adr, size_t size);
+void dsp_cpustat_request(enum e_cpustat req);
+enum e_cpustat dsp_cpustat_get_stat(void);
+unsigned short dsp_cpustat_get_icrmask(void);
+void dsp_cpustat_set_icrmask(unsigned short mask);
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/15: DSP Gateway version 3.2
+ * 2005/06/07: DSP Gateway version 3.3
*/
#include <linux/init.h>
};
static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE;
-static unsigned short mbseq_send;
-static unsigned short mbseq_expect;
-
-struct sync_seq {
- unsigned short da_dsp;
- unsigned short da_arm;
- unsigned short ad_dsp;
- unsigned short ad_arm;
-};
-static struct sync_seq *sync_seq;
+static int mbx1_valid;
+static struct sync_seq *mbseq;
+static unsigned short mbseq_expect_tmp;
+static unsigned short *mbseq_expect = &mbseq_expect_tmp;
/*
* mailbox commands
extern void mbx1_bksndp(struct mbcmd *mb);
extern void mbx1_bkreqp(struct mbcmd *mb);
extern void mbx1_tctl(struct mbcmd *mb);
+extern void mbx1_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
extern void mbx1_wdt(struct mbcmd *mb);
+#endif
extern void mbx1_suspend(struct mbcmd *mb);
static void mbx1_kfunc(struct mbcmd *mb);
extern void mbx1_tcfg(struct mbcmd *mb);
cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp },
cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp },
cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl },
+ cif_poll = { "POLL", CMD_L_TYPE_NULL, mbx1_poll },
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_wdt },
+#endif
cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL },
cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL },
cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend },
&cif_bksndp, &cif_bkreqp, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
-/*30*/ &cif_tctl, &cif_null, &cif_null, &cif_null,
+/*30*/ &cif_tctl, &cif_null, &cif_poll, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
/*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend,
+#else
+/*50*/ &cif_null, &cif_runlevel, &cif_pm, &cif_suspend,
+#endif
&cif_kfunc, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null,
#define print_mb_mmu_abort(mb) do {} while(0)
#endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */
-int __mbsend(struct mbcmd *mb)
+int __mbcmd_send(struct mbcmd *mb)
{
struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
unsigned long flags;
return -1;
}
- mb->seq = mbseq_send & 1;
- mbseq_send++;
- if (sync_seq)
- sync_seq->ad_arm = mbseq_send;
- mblog_add(mb, MBLOG_DIR_AD);
- mblog_printcmd(mb, MBLOG_DIR_AD);
+ if (mbseq) {
+ mb->seq = mbseq->ad_arm;
+ mbseq->ad_arm++;
+ } else
+ mb->seq = 0;
+ mblog_add(mb, DIR_A2D);
+ mblog_printcmd(mb, DIR_A2D);
omap_writew(mb_hw->data, MAILBOX_ARM2DSP1);
omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b);
}
/*
- * __dsp_mbsend(): mailbox dispatcher
+ * __dsp_mbcmd_send(): mailbox dispatcher
*/
-int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
+int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
{
static DECLARE_MUTEX(mbsend_sem);
int ret = 0;
if (arg) { /* we have extra argument */
int i;
- if (__dsp_mem_enable(ipbuf_sys_ad) < 0)
- goto out;
+ /*
+ * even if ipbuf_sys_ad is in DSP internal memory,
+ * dsp_mem_enable() never cause to call PM mailbox command
+ * because in that case DSP memory should be always enabled.
+ * (see ipbuf_sys_hold_mem_active in ipbuf.c)
+ *
+ * Therefore, we can call this function here safely.
+ */
+ dsp_mem_enable(ipbuf_sys_ad);
if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) {
printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+ dsp_mem_disable(ipbuf_sys_ad);
ret = -EBUSY;
goto out;
}
ipbuf_sys_ad->d[i] = arg->argv[i];
}
ipbuf_sys_ad->s = arg->tid;
- if (__dsp_mem_disable(ipbuf_sys_ad) < 0)
- goto out;
+ dsp_mem_disable(ipbuf_sys_ad);
}
- ret = __mbsend(mb);
+ ret = __mbcmd_send(mb);
out:
up(&mbsend_sem);
return ret;
}
-int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
- wait_queue_head_t *q)
+int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q)
{
long current_state;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(q, &wait);
current_state = current->state;
set_current_state(TASK_INTERRUPTIBLE);
- if (dsp_mbsend_exarg(mb, arg) < 0) {
+ if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
set_current_state(current_state);
remove_wait_queue(q, &wait);
return -1;
}
- schedule();
+ schedule_timeout(DSP_TIMEOUT);
set_current_state(current_state);
remove_wait_queue(q, &wait);
return 0;
}
+int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
+ int recovery_flag)
+{
+ struct mbcmd mb;
+
+ mbcmd_set(mb, cmdh, cmdl, data);
+ return __dsp_mbcmd_send(&mb, NULL, recovery_flag);
+}
+
+static int mbsync_hold_mem_active;
+
void dsp_mb_start(void)
{
- mbseq_send = 0;
- mbseq_expect = 0;
+ mbx1_valid = 1; /* start interpreting */
+ mbseq_expect_tmp = 0;
}
void dsp_mb_stop(void)
{
- sync_seq = NULL;
+ mbx1_valid = 0; /* stop interpreting */
+ if (mbsync_hold_mem_active) {
+ dsp_mem_disable((void *)daram_base);
+ mbsync_hold_mem_active = 0;
+ }
+ mbseq = NULL;
+ mbseq_expect = &mbseq_expect_tmp;
}
-/*
- * dsp_mb_config() is called from mbx1 workqueue
- */
-void dsp_mb_config(void *sync_seq_adr)
+int dsp_mb_config(void *p)
{
- sync_seq = sync_seq_adr;
- sync_seq->da_arm = mbseq_expect;
+ unsigned long flags;
+
+ if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
+ return -1;
+ if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
+ printk(KERN_WARNING
+ "omapdsp: mbseq is placed in DSP internal memory.\n"
+ " It will prevent DSP from idling.\n");
+ mbsync_hold_mem_active = 1;
+ /*
+ * dsp_mem_enable() never fails because
+ * it has been already enabled in dspcfg process and
+ * this will just increment the usecount.
+ */
+ dsp_mem_enable((void *)daram_base);
+ }
+
+ local_irq_save(flags);
+ mbseq = p;
+ mbseq->da_arm = mbseq_expect_tmp;
+ mbseq_expect = &mbseq->da_arm;
+ local_irq_restore(flags);
+
+ return 0;
}
/*
mb = &mbq.mb[mbq.rp];
- mblog_add(mb, MBLOG_DIR_DA);
- mblog_printcmd(mb, MBLOG_DIR_DA);
+ mblog_add(mb, DIR_D2A);
+ mblog_printcmd(mb, DIR_D2A);
/*
* call handler for each command
/*
* kernel function dispatcher
*/
-#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
extern void mbx1_fbctl_disable(void);
static void mbx1_kfunc_fbctl(unsigned short data)
"mailbox: Unknown FBCTL from DSP: 0x%04x\n", data);
}
}
-#endif
static void mbx1_kfunc(struct mbcmd *mb)
{
switch (mb->cmd_l) {
-#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
case OMAP_DSP_MBCMD_KFUNC_FBCTL:
mbx1_kfunc_fbctl(mb->data);
break;
-#endif
default:
printk(KERN_ERR
mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM2b);
#endif
- if (mb->sw.seq != (mbseq_expect & 1)) {
+ /* if mbx1 has not been validated yet, discard. */
+ if (!mbx1_valid)
+ return IRQ_HANDLED;
+
+ if (mb->sw.seq != (*mbseq_expect & 1)) {
switch (mbseq_check_level) {
case MBSEQ_CHECK_NONE:
break;
}
}
- mbseq_expect++;
- if (sync_seq)
- sync_seq->da_arm = mbseq_expect;
+ (*mbseq_expect)++;
mbq_inc(mbq.wp);
if (mbq.wp == mbq.rp) { /* mbq is full */
goto fail6;
}
+ /* MMU interrupt is not enabled until DSP runs */
+ disable_irq(INT_DSP_MMU);
+
#if 0
ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev);
if (ret) {
static int dsp_drv_remove(struct device *dev)
{
- __dsp_reset();
+ dsp_cpustat_request(CPUSTAT_RESET);
#if 0
free_irq(INT_MPUIO, dev);
free_irq(INT_D2A_MB2, dev);
free_irq(INT_D2A_MB1, dev);
+ /* recover disable_depth */
+ enable_irq(INT_DSP_MMU);
+
dspuncfg();
dsp_taskmod_exit();
mblog_exit();
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/17: DSP Gateway version 3.2
+ * 2005/06/09: DSP Gateway version 3.3
*/
#include <linux/module.h>
static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
extern struct device_attribute dev_attr_ipbuf;
-static enum {
+static enum cfgstat {
CFG_ERR,
CFG_READY,
CFG_SUSPEND
} cfgstat;
-static int mbx_revision;
+int mbx_revision;
static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q);
static unsigned short ioctl_wait_cmd;
static DECLARE_MUTEX(ioctl_sem);
/*
* control functions
*/
-static void dsp_run(void)
-{
- disable_irq(INT_DSP_MMU);
- preempt_disable();
- if (dsp_runstat == RUNSTAT_RESET) {
- clk_use(api_ck_handle);
- __dsp_run();
- dsp_runstat = RUNSTAT_RUN;
- }
- preempt_enable();
- enable_irq(INT_DSP_MMU);
-}
-
-static void dsp_reset(void)
-{
- disable_irq(INT_DSP_MMU);
- preempt_disable();
- if (dsp_runstat > RUNSTAT_RESET) {
- __dsp_reset();
- if (dsp_runstat == RUNSTAT_RUN)
- clk_unuse(api_ck_handle);
- dsp_runstat = RUNSTAT_RESET;
- }
- preempt_enable();
- enable_irq(INT_DSP_MMU);
-}
-
static short varread_val[5]; /* maximum */
static int dsp_regread(unsigned short cmd_l, unsigned short adr,
ioctl_wait_cmd = MBCMD(REGRW);
mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
- dsp_mbsend_and_wait(&mb, &ioctl_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: register read error!\n");
};
mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
- dsp_mbsend_exarg(&mb, &arg);
+ dsp_mbcmd_send_exarg(&mb, &arg);
return 0;
}
ioctl_wait_cmd = MBCMD(GETVAR);
mbcmd_set(mb, MBCMD(GETVAR), varid, 0);
- dsp_mbsend_and_wait(&mb, &ioctl_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: variable read error!\n");
static int dsp_setvar(unsigned char varid, unsigned short val)
{
- struct mbcmd mb;
-
- mbcmd_set(mb, MBCMD(SETVAR), varid, val);
- dsp_mbsend(&mb);
+ dsp_mbsend(MBCMD(SETVAR), varid, val);
return 0;
}
goto up_out;
}
+ /* for safety */
+ dsp_mem_usecount_clear();
+
+ /*
+ * DSPCFG command and dsp_mem_start() must be called
+ * while internal mem is on.
+ */
+ dsp_mem_enable((void *)dspmem_base);
+
dsp_mb_start();
dsp_twch_start();
dsp_mem_start();
mbx_revision = -1;
ioctl_wait_cmd = MBCMD(DSPCFG);
mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0);
- dsp_mbsend_and_wait(&mb, &ioctl_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: configuration error!\n");
goto up_out;
}
+#ifdef OLD_BINARY_SUPPORT
+ /*
+ * MBREV 3.2 or earlier doesn't assume DMA domain is on
+ * when DSPCFG command is sent
+ */
+ if ((mbx_revision == MBREV_3_0) ||
+ (mbx_revision == MBREV_3_2)) {
+ ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
+ }
+#endif
+
if ((ret = dsp_task_config_all(n_stask)) < 0) {
up(&ioctl_sem);
dspuncfg();
+ dsp_mem_disable((void *)dspmem_base);
return -EINVAL;
}
cfgstat = CFG_READY;
/* send parameter */
- if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask)) < 0)
+ if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK,
+ dsp_cpustat_get_icrmask())) < 0)
goto up_out;
/* create runtime sysfs entries */
device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
up_out:
+ dsp_mem_disable((void *)dspmem_base);
up(&ioctl_sem);
return ret;
}
if (down_interruptible(&ioctl_sem))
return -ERESTARTSYS;
-
+
/* FIXME: lock task module */
/* remove runtime sysfs entries */
dsp_mb_stop();
dsp_twch_stop();
+ dsp_mem_stop();
dsp_err_stop();
+ dsp_dbg_stop();
dsp_task_unconfig_all();
ipbuf_stop();
cfgstat = CFG_ERR;
return (cfgstat == CFG_READY) ? 1 : 0;
}
-void dsp_runlevel(unsigned char level)
+/*
+ * polls all tasks
+ */
+int dsp_poll(void)
{
struct mbcmd mb;
+ int ret = 0;
- mbcmd_set(mb, MBCMD(RUNLEVEL), level, 0);
+ if (down_interruptible(&ioctl_sem))
+ return -ERESTARTSYS;
+
+ ioctl_wait_cmd = MBCMD(POLL);
+ mbcmd_set(mb, MBCMD(POLL), 0, 0);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
+
+ if (ioctl_wait_cmd != 0) {
+ printk(KERN_ERR "omapdsp: poll error!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+up_out:
+ up(&ioctl_sem);
+ return ret;
+}
+
+void dsp_runlevel(unsigned char level)
+{
if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY)
- dsp_mbsend_recovery(&mb);
+ dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0);
else
- dsp_mbsend(&mb);
+ dsp_mbsend(MBCMD(RUNLEVEL), level, 0);
}
+static enum cfgstat cfgstat_save_suspend;
+
+/*
+ * suspend / resume callbacks
+ * DSP is not reset within this code, but done in omap_pm_suspend.
+ * so if these functions are called as OMAP_DSP_IOCTL_SUSPEND,
+ * DSP should be reset / unreset out of these functions.
+ */
int dsp_suspend(void)
{
struct mbcmd mb;
int ret = 0;
+ if (cfgstat == CFG_SUSPEND) {
+ printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n");
+ return -EINVAL;
+ }
+
if (down_interruptible(&ioctl_sem))
return -ERESTARTSYS;
+ cfgstat_save_suspend = cfgstat;
if (!dsp_is_ready()) {
- ret = -EINVAL;
- goto up_out;
+ if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+ printk(KERN_WARNING
+ "omapdsp: illegal operation: trying suspend DSP "
+ "while it is running but has not configured "
+ "yet.\n"
+ " Resetting DSP...\n");
+ }
+ goto transition;
}
ioctl_wait_cmd = MBCMD(SUSPEND);
mbcmd_set(mb, MBCMD(SUSPEND), 0, 0);
- dsp_mbsend_and_wait(&mb, &ioctl_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: DSP suspend error!\n");
}
udelay(100);
+transition:
cfgstat = CFG_SUSPEND;
up_out:
up(&ioctl_sem);
int dsp_resume(void)
{
- if (cfgstat != CFG_SUSPEND)
- return 0;
+ if (cfgstat != CFG_SUSPEND) {
+ printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n");
+ return -EINVAL;
+ }
- cfgstat = CFG_READY;
+ cfgstat = cfgstat_save_suspend;
return 0;
}
static void dsp_fbctl_enable(void)
{
-#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
- struct mbcmd mb;
-
- mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
- OMAP_DSP_MBCMD_FBCTL_ENABLE);
- dsp_mbsend(&mb);
-#endif
+ dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
+ OMAP_DSP_MBCMD_FBCTL_ENABLE);
}
static int dsp_fbctl_disable(void)
{
int ret = 0;
-
-#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
struct mbcmd mb;
if (down_interruptible(&ioctl_sem))
ioctl_wait_cmd = MBCMD(KFUNC);
mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
OMAP_DSP_MBCMD_FBCTL_DISABLE);
- dsp_mbsend_and_wait(&mb, &ioctl_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: fb disable error!\n");
ret = -EINVAL;
}
up(&ioctl_sem);
-#endif
return ret;
}
* command level 1: commands which don't need lock
*/
case OMAP_DSP_IOCTL_RUN:
- dsp_run();
+ dsp_cpustat_request(CPUSTAT_RUN);
break;
case OMAP_DSP_IOCTL_RESET:
- dsp_reset();
+ dsp_cpustat_request(CPUSTAT_RESET);
break;
case OMAP_DSP_IOCTL_SETRSTVECT:
ret = dsp_set_rstvect((unsigned long)arg);
break;
- case OMAP_DSP_IOCTL_IDLE:
- dsp_idle();
+ case OMAP_DSP_IOCTL_CPU_IDLE:
+ dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+ break;
+
+ case OMAP_DSP_IOCTL_GBL_IDLE:
+ dsp_cpustat_request(CPUSTAT_GBL_IDLE);
break;
case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON:
return -EFAULT;
mb.cmd = u_cmd.cmd;
mb.data = u_cmd.data;
- ret = dsp_mbsend((struct mbcmd *)&mb);
+ ret = dsp_mbcmd_send((struct mbcmd *)&mb);
break;
}
ret = dsp_task_count();
break;
+ case OMAP_DSP_IOCTL_POLL:
+ ret = dsp_poll();
+ break;
+
case OMAP_DSP_IOCTL_FBDIS:
ret = dsp_fbctl_disable();
break;
+ /*
+ * FIXME: cpu status control for suspend - resume
+ */
case OMAP_DSP_IOCTL_SUSPEND:
if ((ret = dsp_suspend()) < 0)
break;
- dsp_reset();
+ dsp_cpustat_request(CPUSTAT_RESET);
break;
case OMAP_DSP_IOCTL_RESUME:
if ((ret = dsp_resume()) < 0)
break;
- dsp_run();
+ dsp_cpustat_request(CPUSTAT_RUN);
break;
case OMAP_DSP_IOCTL_REGMEMR:
{
unsigned char last = mb->cmd_l & 0x80;
unsigned char cfgcmd = mb->cmd_l & 0x7f;
- static unsigned long tmp_ipbuf_sys_da;
+ static unsigned long tmp_ipb_adr;
/* mailbox protocol check */
if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) {
if (mbx_revision == OMAP_DSP_MBPROT_REVISION)
return;
#ifdef OLD_BINARY_SUPPORT
- else if (mbx_revision == MBREV_3_0) {
+ else if ((mbx_revision == MBREV_3_0) ||
+ (mbx_revision == MBREV_3_2)) {
printk(KERN_WARNING
"mbx: ***** old DSP binary *****\n"
" Please update your DSP application.\n");
" expected=0x%04x, received=0x%04x\n",
OMAP_DSP_MBPROT_REVISION, mb->data);
mbx_revision = -1;
- goto abort;
+ goto abort1;
}
}
switch (cfgcmd) {
case OMAP_DSP_MBCMD_DSPCFG_SYSADRH:
- tmp_ipbuf_sys_da = (unsigned long)mb->data << 16;
+ tmp_ipb_adr = (unsigned long)mb->data << 16;
break;
case OMAP_DSP_MBCMD_DSPCFG_SYSADRL:
- tmp_ipbuf_sys_da |= mb->data;
+ tmp_ipb_adr |= mb->data;
break;
case OMAP_DSP_MBCMD_DSPCFG_ABORT:
- goto abort;
+ goto abort1;
default:
printk(KERN_ERR
}
if (last) {
- unsigned long badr;
+ void *badr;
unsigned short bln;
unsigned short bsz;
volatile unsigned short *buf;
- void *sync_seq;
+ void *ipb_sys_da, *ipb_sys_ad;
+ void *mbseq;
+ short *dbg_buf;
+ unsigned short dbg_buf_sz, dbg_line_sz;
+ struct mem_sync_struct mem_sync, *mem_syncp;
- /* system IPBUF initialization */
- if (tmp_ipbuf_sys_da & 0x1) {
- printk(KERN_ERR
- "mbx: system ipbuf address (0x%lx) "
- "is odd number!\n", tmp_ipbuf_sys_da);
- goto abort;
- }
- ipbuf_sys_da = dspword_to_virt(tmp_ipbuf_sys_da);
+ ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+ if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+ goto abort1;
if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n");
- return;
+ goto abort1;
}
/*
* read configuration data on system IPBUF
if (mbx_revision == OMAP_DSP_MBPROT_REVISION) {
#endif
buf = ipbuf_sys_da->d;
- n_stask = buf[0];
- bln = buf[1];
- bsz = buf[2];
- badr = MKLONG(buf[3], buf[4]);
- /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[5], buf[6])); */
- ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[7], buf[8]));
- sync_seq = dspword_to_virt(MKLONG(buf[9], buf[10]));
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
+ ipb_sys_ad = MKVIRT(buf[7], buf[8]);
+ mbseq = MKVIRT(buf[9], buf[10]);
+ dbg_buf = MKVIRT(buf[11], buf[12]);
+ dbg_buf_sz = buf[13];
+ dbg_line_sz = buf[14];
+ mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
+ mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
+ mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
+ mem_syncp = &mem_sync;
#ifdef OLD_BINARY_SUPPORT
+ } else if (mbx_revision == MBREV_3_2) {
+ buf = ipbuf_sys_da->d;
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
+ ipb_sys_ad = MKVIRT(buf[7], buf[8]);
+ mbseq = MKVIRT(buf[9], buf[10]);
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ mem_syncp = NULL;
} else if (mbx_revision == MBREV_3_0) {
buf = ipbuf_sys_da->d;
- n_stask = buf[0];
- bln = buf[1];
- bsz = buf[2];
- badr = MKLONG(buf[3], buf[4]);
- /* bkeep = buf[5]; */
- /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[6], buf[67)); */
- ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[8], buf[9]));
- sync_seq = dspword_to_virt(MKLONG(buf[10], buf[11]));
+ n_stask = buf[0];
+ bln = buf[1];
+ bsz = buf[2];
+ badr = MKVIRT(buf[3], buf[4]);
+ /* bkeep = buf[5]; */
+ /* ipb_sys_da = MKVIRT(buf[6], buf[7]); */
+ ipb_sys_ad = MKVIRT(buf[8], buf[9]);
+ mbseq = MKVIRT(buf[10], buf[11]);
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ mem_syncp = NULL;
} else /* should not occur */
- goto abort;
-#endif
-
- /* ipbuf_config() should be done in interrupt routine. */
- if (ipbuf_config(bln, bsz, badr) < 0)
- goto abort;
+ goto abort1;
+#endif /* OLD_BINARY_SUPPORT */
- ipbuf_sys_da->s = OMAP_DSP_TID_FREE;
+ release_ipbuf_pvt(ipbuf_sys_da);
- /* mb_config() should be done in interrupt routine. */
- dsp_mb_config(sync_seq);
+ /*
+ * following configurations need to be done before
+ * waking up the dspcfg initiator process.
+ */
+ if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
+ goto abort1;
+ if (ipbuf_config(bln, bsz, badr) < 0)
+ goto abort1;
+ if (dsp_mb_config(mbseq) < 0)
+ goto abort2;
+ if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
+ goto abort2;
+ if (dsp_mem_sync_config(mem_syncp) < 0)
+ goto abort2;
ioctl_wait_cmd = 0;
wake_up_interruptible(&ioctl_wait_q);
}
return;
-abort:
+abort2:
+ ipbuf_stop();
+abort1:
wake_up_interruptible(&ioctl_wait_q);
return;
}
+void mbx1_poll(struct mbcmd *mb)
+{
+ if (!waitqueue_active(&ioctl_wait_q) ||
+ (ioctl_wait_cmd != MBCMD(POLL))) {
+ printk(KERN_WARNING
+ "mbx: POLL command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ ioctl_wait_cmd = 0;
+ wake_up_interruptible(&ioctl_wait_q);
+}
+
void mbx1_regrw(struct mbcmd *mb)
{
if (!waitqueue_active(&ioctl_wait_q) ||
for (i = 0; i < 5; i++) {
varread_val[i] = buf[i];
}
- ipbuf_sys_da->s = OMAP_DSP_TID_FREE;
+ release_ipbuf_pvt(ipbuf_sys_da);
break;
}
}
*
* 3.2: sysfs / udev support
* KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+ * 3.3: added following ioctls
+ * OMAP_DSP_IOCTL_GBL_IDLE
+ * OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE)
+ * OMAP_DSP_IOCTL_POLL
*/
/*
* print all supporting I/F VERSIONs, like followings.
*
- * len += sprintf(buf, "3.1\n");
* len += sprintf(buf, "3.2\n");
+ * len += sprintf(buf, "3.3\n");
*/
len += sprintf(buf + len, "3.2\n");
+ len += sprintf(buf + len, "3.3\n");
return len;
}
static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
-static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
-#if 0
- if (dsp_is_ready()) {
- int ret;
- unsigned short val;
+ return sprintf(buf, "%s\n", cpustat_name(dsp_cpustat_get_stat()));
+}
- if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_ICRMASK, &val, 1)) < 0)
- return ret;
- if (val != dsp_icrmask)
- printk(KERN_WARNING
- "omapdsp: icrmask value is inconsistent!\n");
- }
-#endif
- return sprintf(buf, "0x%04x\n", dsp_icrmask);
+static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
+
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
}
static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ unsigned short mask;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- dsp_icrmask = simple_strtol(buf, NULL, 16);
+ mask = simple_strtol(buf, NULL, 16);
+ dsp_cpustat_set_icrmask(mask);
if (dsp_is_ready()) {
- ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask);
+ ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask);
if (ret < 0)
return ret;
}
* static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
*/
-#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
void mbx1_fbctl_disable(void)
{
if (!waitqueue_active(&ioctl_wait_q) ||
ioctl_wait_cmd = 0;
wake_up_interruptible(&ioctl_wait_q);
}
-#endif
#ifdef CONFIG_PROC_FS
/* for backward compatibility */
void __init dsp_ctl_init(void)
{
device_create_file(&dsp_device.dev, &dev_attr_ifver);
+ device_create_file(&dsp_device.dev, &dev_attr_cpustat);
device_create_file(&dsp_device.dev, &dev_attr_icrmask);
#ifdef CONFIG_PROC_FS
dsp_ctl_create_proc();
void dsp_ctl_exit(void)
{
device_remove_file(&dsp_device.dev, &dev_attr_ifver);
+ device_remove_file(&dsp_device.dev, &dev_attr_cpustat);
device_remove_file(&dsp_device.dev, &dev_attr_icrmask);
#ifdef CONFIG_PROC_FS
dsp_ctl_remove_proc();
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/10: DSP Gateway version 3.2
+ * 2005/07/26: DSP Gateway version 3.3
*/
#include <linux/module.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <asm/arch/dsp.h>
#include "hardware_dsp.h"
static const struct dev_list {
unsigned int minor;
char *devname;
- char *devfs_name;
umode_t mode;
} dev_list[] = {
- {CTL_MINOR, "dspctl", "dspctl/ctl", S_IRUSR | S_IWUSR},
- {MEM_MINOR, "dspmem", "dspctl/mem", S_IRUSR | S_IWUSR | S_IRGRP},
- {TWCH_MINOR, "dsptwch", "dspctl/twch", S_IRUSR | S_IWUSR | S_IRGRP},
- {ERR_MINOR, "dsperr", "dspctl/err", S_IRUSR | S_IRGRP},
+ {CTL_MINOR, "dspctl", S_IRUSR | S_IWUSR},
+ {MEM_MINOR, "dspmem", S_IRUSR | S_IWUSR | S_IRGRP},
+ {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
+ {ERR_MINOR, "dsperr", S_IRUSR | S_IRGRP},
};
int __init dsp_ctl_core_init(void)
}
dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
- devfs_mk_dir("dspctl");
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
class_device_create(dsp_ctl_class,
MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor),
NULL, dev_list[i].devname);
- devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor),
- S_IFCHR | dev_list[i].mode,
- dev_list[i].devfs_name);
}
return 0;
int i;
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- devfs_remove(dev_list[i].devfs_name);
class_device_destroy(dsp_ctl_class,
MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor));
}
- devfs_remove("dspctl");
class_destroy(dsp_ctl_class);
unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- * 2005/02/17: DSP Gateway version 3.2
+ * 2005/06/09: DSP Gateway version 3.3
*/
#include <linux/module.h>
#include <asm/hardware/clock.h>
#include <asm/arch/tc.h>
#include <asm/arch/dsp.h>
+#include <asm/arch/dsp_common.h>
#include "uaccess_dsp.h"
-#include "ipbuf.h"
#include "dsp.h"
#define SZ_1MB 0x100000
struct exmap_tbl {
unsigned int valid:1;
unsigned int cntnu:1; /* grouping */
+ int usecount; /* reference count by mmap */
enum exmap_type type;
- void *buf;
- void *vadr;
+ void *buf; /* virtual address of the buffer,
+ * i.e. 0xc0000000 - */
+ void *vadr; /* DSP shadow space,
+ * i.e. 0xe0000000 - 0xe0ffffff */
unsigned int order;
};
#define DSPMMU_TLB_LINES 32
static void *dspvect_page;
static unsigned long dsp_fault_adr;
+static struct mem_sync_struct mem_sync;
static __inline__ unsigned long lineup_offset(unsigned long adr,
unsigned long ref,
return newadr;
}
+void dsp_mem_sync_inc(void)
+{
+ /*
+ * FIXME: dsp_mem_enable()!!!
+ */
+ if (mem_sync.DARAM)
+ mem_sync.DARAM->ad_arm++;
+ if (mem_sync.SARAM)
+ mem_sync.SARAM->ad_arm++;
+ if (mem_sync.SDRAM)
+ mem_sync.SDRAM->ad_arm++;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbx1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+ size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+ if (sync == NULL) {
+ memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+ return 0;
+ }
+#endif
+ if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+ (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+ (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+ printk(KERN_ERR
+ "omapdsp: mem_sync address validation failure!\n"
+ " mem_sync.DARAM = 0x%p,\n"
+ " mem_sync.SARAM = 0x%p,\n"
+ " mem_sync.SDRAM = 0x%p,\n",
+ sync->DARAM, sync->SARAM, sync->SDRAM);
+ return -1;
+ }
+ memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+ return 0;
+}
+
/*
* kmem_reserve(), kmem_release():
* reserve or release kernel memory for exmap().
return __get_dma_pages(GFP_KERNEL, order);
}
-static void dsp_mem_free_pages(unsigned int buf, unsigned int order)
+static void dsp_mem_free_pages(unsigned long buf, unsigned int order)
{
struct kmem_pool *pool;
+ struct page *page, *ps, *pe;
int i;
+ ps = virt_to_page(buf);
+ pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+ for (page = ps; page < pe; page++) {
+ ClearPageReserved(page);
+ }
+
+ /*
+ * return buffer to kmem_pool or paging system
+ */
switch (order) {
case ORDER_1MB:
pool = &kmem_pool_1M;
static int exmap_valid(void *vadr, size_t len)
{
+ /* exmap_sem should be held before calling this function */
int i;
start:
return 0;
}
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+ void *ds = (void *)daram_base;
+ void *de = (void *)daram_base + daram_size;
+ void *ss = (void *)saram_base;
+ void *se = (void *)saram_base + saram_size;
+ int ret;
+
+ if ((vadr >= ds) && (vadr < de)) {
+ if (vadr + len > de)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_DARAM;
+ } else if ((vadr >= ss) && (vadr < se)) {
+ if (vadr + len > se)
+ return MEM_TYPE_CROSSING;
+ else
+ return MEM_TYPE_SARAM;
+ } else {
+ down_read(&exmap_sem);
+ if (exmap_valid(vadr, len))
+ ret = MEM_TYPE_EXTERN;
+ else
+ ret = MEM_TYPE_NONE;
+ up_read(&exmap_sem);
+ return ret;
+ }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+ if (dsp_mem_type(p, len) <= 0) {
+ if (fmt != NULL) {
+ char s[64];
+ va_list args;
+
+ va_start(args, fmt);
+ vsprintf(s, fmt, args);
+ va_end(args);
+ printk(KERN_ERR
+ "omapdsp: %s address(0x%p) and size(0x%x) is "
+ "not valid!\n"
+ " (crossing different type of memories, or \n"
+ " external memory space where no "
+ "actual memory is mapped)\n",
+ s, p, len);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void exmap_use(void *vadr, size_t len)
+{
+ int i;
+
+ down_write(&exmap_sem);
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
+ ent->usecount++;
+ }
+ }
+ up_write(&exmap_sem);
+}
+
+void exmap_unuse(void *vadr, size_t len)
+{
+ int i;
+
+ down_write(&exmap_sem);
+ for (i = 0; i < DSPMMU_TLB_LINES; i++) {
+ void *mapadr;
+ unsigned long mapsize;
+ struct exmap_tbl *ent = &exmap_tbl[i];
+
+ if (!ent->valid)
+ continue;
+ mapadr = (void *)ent->vadr;
+ mapsize = 1 << (ent->order + PAGE_SHIFT);
+ if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
+ ent->usecount--;
+ }
+ }
+ up_write(&exmap_sem);
+}
+
/*
* dsp_virt_to_phys()
* returns physical address, and sets len to valid length
goto fail;
}
- exmap_ent->buf = buf;
- exmap_ent->vadr = _vadr;
- exmap_ent->order = order;
- exmap_ent->valid = 1;
- exmap_ent->cntnu = cntnu;
- exmap_ent->type = type;
+ exmap_ent->buf = buf;
+ exmap_ent->vadr = _vadr;
+ exmap_ent->order = order;
+ exmap_ent->valid = 1;
+ exmap_ent->cntnu = cntnu;
+ exmap_ent->type = type;
+ exmap_ent->usecount = 0;
if ((_size -= unit) == 0) { /* normal completion */
up_write(&exmap_sem);
return -EINVAL;
found_map:
+ if (ent->usecount > 0) {
+ printk(KERN_ERR
+ "omapdsp: exmap reference count is not 0.\n"
+ " idx=%d, vadr=%p, order=%d, usecount=%d\n",
+ idx, ent->vadr, ent->order, ent->usecount);
+ up_write(&exmap_sem);
+ return -EINVAL;
+ }
/* clearing DSP TLB entry */
dsp_mmu_clear_tlb(dspadr);
/* flush TLB */
flush_tlb_kernel_range(dspmem_base + dspmem_size,
dspmem_base + DSPSPACE_SIZE);
- /*
- * we should clear processes' mm as well,
- * because processes might had accessed to those spaces
- * with old table in the past.
- */
up_write(&exmap_sem);
}
phys = __pa(dspvect_page);
virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */
exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
- exmap_tbl[0].buf = dspvect_page;
- exmap_tbl[0].vadr = virt;
- exmap_tbl[0].order = 0;
- exmap_tbl[0].valid = 1;
- exmap_tbl[0].cntnu = 0;
+ exmap_tbl[0].buf = dspvect_page;
+ exmap_tbl[0].vadr = virt;
+ exmap_tbl[0].usecount = 0;
+ exmap_tbl[0].order = 0;
+ exmap_tbl[0].valid = 1;
+ exmap_tbl[0].cntnu = 0;
/* DSP TLB initialization */
set_tlb_lock(0, 0);
}
/*
- * dsp_mem_enable() / disable():
+ * intmem_enable() / disable():
* if the address is in DSP internal memories,
* we send PM mailbox commands so that DSP DMA domain won't go in idle
* when ARM is accessing to those memories.
- * if the address is in external memory, acquire exmap_sem.
- *
- * __dsp_mem_enable() / disable() should be called only from __dsp_mbsend().
*/
-static int dsp_mem_en_count;
-
-int dsp_mem_enable(void *adr)
+static int intmem_enable(void)
{
- struct mbcmd mb;
- int ret;
+ int ret = 0;
- if (is_dsp_internal_mem(adr)) {
- if (dsp_is_ready() && (!dsp_mem_en_count) &&
- (dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) {
- mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
- DSPREG_ICR_DMA_IDLE_DOMAIN);
- if ((ret = dsp_mbsend(&mb)) < 0)
- return ret;
- dsp_mem_en_count++;
- }
- } else
- down_read(&exmap_sem);
- return 0;
-}
+ if (dsp_is_ready())
+ ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
-int dsp_mem_disable(void *adr)
-{
- struct mbcmd mb;
- int ret;
+ return ret;
+}
- if (is_dsp_internal_mem(adr)) {
- if (dsp_is_ready() && dsp_mem_en_count) {
- mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE,
- DSPREG_ICR_DMA_IDLE_DOMAIN);
- if ((ret = dsp_mbsend(&mb)) < 0)
- return ret;
- dsp_mem_en_count--;
- }
- } else
- up_read(&exmap_sem);
- return 0;
+static void intmem_disable(void) {
+ if (dsp_is_ready())
+ dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE,
+ DSPREG_ICR_DMA_IDLE_DOMAIN);
}
-int __dsp_mem_enable(void *adr)
+/*
+ * dsp_mem_enable() / disable()
+ */
+int intmem_usecount;
+
+int dsp_mem_enable(void *adr)
{
- struct mbcmd mb;
- int ret;
+ int ret = 0;
if (is_dsp_internal_mem(adr)) {
- if (dsp_is_ready() && (!dsp_mem_en_count) &&
- (dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) {
- mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
- DSPREG_ICR_DMA_IDLE_DOMAIN);
- if ((ret = __mbsend(&mb)) < 0)
- return ret;
- dsp_mem_en_count++;
- }
+ if (intmem_usecount++ == 0)
+ ret = omap_dsp_request_mem();
} else
down_read(&exmap_sem);
- return 0;
+
+ return ret;
}
-int __dsp_mem_disable(void *adr)
+void dsp_mem_disable(void *adr)
{
- struct mbcmd mb;
- int ret;
-
if (is_dsp_internal_mem(adr)) {
- if (dsp_is_ready() && dsp_mem_en_count) {
- mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE,
- DSPREG_ICR_DMA_IDLE_DOMAIN);
- if ((ret = __mbsend(&mb)) < 0)
- return ret;
- dsp_mem_en_count--;
- }
+ if (--intmem_usecount == 0)
+ omap_dsp_release_mem();
} else
up_read(&exmap_sem);
- return 0;
+}
+
+/* for safety */
+void dsp_mem_usecount_clear(void)
+{
+ if (intmem_usecount != 0) {
+ printk(KERN_WARNING
+ "omapdsp: unbalanced memory request/release detected.\n"
+ " intmem_usecount is not zero at where "
+ "it should be! ... fixed to be zero.\n");
+ intmem_usecount = 0;
+ omap_dsp_release_mem();
+ }
}
/*
read = size - p;
if (copy_to_user(buf, vadr, read)) {
read = -EFAULT;
- goto finish;
+ goto out;
}
*ppos += read;
-finish:
+out:
clk_unuse(api_ck_handle);
return read;
}
{
unsigned long p = *ppos;
void *vadr = dspbyte_to_virt(p);
- ssize_t ret;
- down_read(&exmap_sem);
if (!exmap_valid(vadr, count)) {
printk(KERN_ERR
"omapdsp: DSP address %08lx / size %08x "
"is not valid!\n", p, count);
- ret = -EFAULT;
- goto up_out;
+ return -EFAULT;
}
if (count > DSPSPACE_SIZE - p)
count = DSPSPACE_SIZE - p;
- if (copy_to_user(buf, vadr, count)) {
- ret = -EFAULT;
- goto up_out;
- }
+ if (copy_to_user(buf, vadr, count))
+ return -EFAULT;
*ppos += count;
- up_read(&exmap_sem);
return count;
-
-up_out:
- up_read(&exmap_sem);
- return ret;
}
static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
+ int ret;
+ void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+ if (dsp_mem_enable(vadr) < 0)
+ return -EBUSY;
if (is_dspbyte_internal_mem(*ppos))
- return intmem_read(file, buf, count, ppos);
+ ret = intmem_read(file, buf, count, ppos);
else
- return exmem_read(file, buf, count, ppos);
+ ret = exmem_read(file, buf, count, ppos);
+ dsp_mem_disable(vadr);
+
+ return ret;
}
static ssize_t intmem_write(struct file *file, const char *buf, size_t count,
written = size - p;
if (copy_from_user(vadr, buf, written)) {
written = -EFAULT;
- goto finish;
+ goto out;
}
*ppos += written;
-finish:
+out:
clk_unuse(api_ck_handle);
return written;
}
{
unsigned long p = *ppos;
void *vadr = dspbyte_to_virt(p);
- ssize_t ret;
- down_read(&exmap_sem);
if (!exmap_valid(vadr, count)) {
printk(KERN_ERR
"omapdsp: DSP address %08lx / size %08x "
"is not valid!\n", p, count);
- ret = -EFAULT;
- goto up_out;
+ return -EFAULT;
}
if (count > DSPSPACE_SIZE - p)
count = DSPSPACE_SIZE - p;
- if (copy_from_user(vadr, buf, count)) {
- ret = -EFAULT;
- goto up_out;
- }
+ if (copy_from_user(vadr, buf, count))
+ return -EFAULT;
*ppos += count;
- up_read(&exmap_sem);
return count;
-
-up_out:
- up_read(&exmap_sem);
- return ret;
}
static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count,
loff_t *ppos)
{
+ int ret;
+ void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
+
+ if (dsp_mem_enable(vadr) < 0)
+ return -EBUSY;
if (is_dspbyte_internal_mem(*ppos))
- return intmem_write(file, buf, count, ppos);
+ ret = intmem_write(file, buf, count, ppos);
else
- return exmem_write(file, buf, count, ppos);
+ ret = exmem_write(file, buf, count, ppos);
+ dsp_mem_disable(vadr);
+
+ return ret;
}
static int dsp_mem_ioctl(struct inode *inode, struct file *file,
{
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- if (dsp_mem_enable((void *)dspmem_base) < 0)
- return -EBUSY;
return 0;
}
static int dsp_mem_release(struct inode *inode, struct file *file)
{
- dsp_mem_disable((void *)dspmem_base);
return 0;
}
down_read(&exmap_sem);
len = sprintf(buf, "v: valid, c: cntnu\n"
- "ety vadr buf od\n");
+ "ety vadr buf od uc\n");
/* 00: v c 0xe0300000 0xc0171800 0 */
for (i = 0; i < DSPMMU_TLB_LINES; i++) {
struct exmap_tbl *ent = &exmap_tbl[i];
/* 00: v c 0xe0300000 0xc0171800 0 */
- len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d\n",
+ len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d %2d\n",
i,
ent->valid ? 'v' : ' ',
ent->cntnu ? 'c' : ' ',
- ent->vadr, ent->buf, ent->order);
+ ent->vadr, ent->buf, ent->order, ent->usecount);
}
up_read(&exmap_sem);
static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap);
+static ssize_t kmem_pool_show(struct device *dev, char *buf)
+{
+ int count_1M, count_64K, total;
+
+ count_1M = kmem_pool_1M.count;
+ count_64K = kmem_pool_64K.count;
+ total = count_1M * SZ_1MB + count_64K * SZ_64KB;
+
+ return sprintf(buf, "0x%x %d %d\n", total, count_1M, count_64K);
+}
+
+static struct device_attribute dev_attr_kmem_pool = __ATTR_RO(kmem_pool);
+
/*
* DSP MMU interrupt handler
*/
/* FIXME */
dsp_err_mmu_set(dsp_fault_adr);
} else {
+ disable_irq(INT_DSP_MMU);
+ __dsp_mmu_itack();
printk(KERN_INFO "Resetting DSP...\n");
- __dsp_reset();
- clk_unuse(api_ck_handle);
+ dsp_cpustat_request(CPUSTAT_RESET);
+ enable_irq(INT_DSP_MMU);
/*
* if we enable followings, semaphore lock should be avoided.
*
void dsp_mem_start(void)
{
- dsp_mem_en_count = 0;
+ dsp_register_mem_cb(intmem_enable, intmem_disable);
+}
+
+void dsp_mem_stop(void)
+{
+ memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+ dsp_unregister_mem_cb();
}
int __init dsp_mem_init(void)
device_create_file(&dsp_device.dev, &dev_attr_mmu);
device_create_file(&dsp_device.dev, &dev_attr_exmap);
+ device_create_file(&dsp_device.dev, &dev_attr_kmem_pool);
return 0;
}
if (dspvect_page != NULL) {
unsigned long virt;
- pmd_t *pmdp;
- pte_t *ptep;
+ down_read(&exmap_sem);
+
+ virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE);
+ flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
free_page((unsigned long)dspvect_page);
dspvect_page = NULL;
- virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE);
- pmdp = pmd_offset(pgd_offset_k(virt), virt);
- ptep = pte_offset_kernel(pmdp, 0);
- pmd_clear(pmdp);
- pte_free_kernel(ptep);
+ up_read(&exmap_sem);
}
device_remove_file(&dsp_device.dev, &dev_attr_mmu);
device_remove_file(&dsp_device.dev, &dev_attr_exmap);
+ device_remove_file(&dsp_device.dev, &dev_attr_kmem_pool);
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/11/22: DSP Gateway version 3.2
+ * 2005/03/11: DSP Gateway version 3.3
*/
#include <linux/module.h>
/*
* functions called from mailbox1 interrupt routine
*/
-void mbx1_wdt(struct mbcmd *mb)
+static void mbx1_err_wdt(unsigned short data)
{
- printk(KERN_WARNING "omapdsp: DSP WDT expired!\n");
errcode |= OMAP_DSP_ERRDT_WDT;
errcnt++;
- wdtval = mb->data;
+ wdtval = data;
wake_up_interruptible(&err_wait_q);
}
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbx1_wdt(struct mbcmd *mb)
+{
+ mbx1_err_wdt(mb->data);
+}
+#endif
+
extern void mbx1_err_ipbfull(void);
extern void mbx1_err_fatal(unsigned char tid);
tid = mb->data & 0x00ff;
mbx1_err_fatal(tid);
break;
+
+ case OMAP_DSP_EID_WDT:
+ mbx1_err_wdt(mb->data);
+ break;
}
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/24: DSP Gateway version 3.2
+ * 2005/02/24: DSP Gateway version 3.3
*/
struct fifo_struct {
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/09/30: DSP Gateway version 3.2
+ * 2005/05/30: DSP Gateway version 3.3
*/
#ifndef __OMAP_DSP_HARDWARE_DSP_H
#define __OMAP_DSP_HARDWARE_DSP_H
+#ifdef CONFIG_ARCH_OMAP1510
+#define OMAP1510_DARAM_BASE 0xe0000000
+#define OMAP1510_DARAM_SIZE 0x10000
+#define OMAP1510_SARAM_BASE 0xe0010000
+#define OMAP1510_SARAM_SIZE 0x18000
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+#define OMAP16XX_DARAM_BASE 0xe0000000
+#define OMAP16XX_DARAM_SIZE 0x10000
+#define OMAP16XX_SARAM_BASE 0xe0010000
+#define OMAP16XX_SARAM_SIZE 0x18000
+#endif
+
/*
* MAJOR device number: !! allocated arbitrary !!
*/
/*
* DSP ICR
*/
+#define DSPREG_ICR_RESERVED_BITS 0xffc0
#define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020
#define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010
#define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/17: DSP Gateway version 3.2
+ * 2005/06/06: DSP Gateway version 3.3
*/
#include <linux/init.h>
struct ipbcfg ipbcfg;
struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
static struct ipblink ipb_free = IPBLINK_INIT;
+static int ipbuf_sys_hold_mem_active;
void ipbuf_stop(void)
{
+ int i;
+
+ spin_lock(&ipb_free.lock);
+ INIT_IPBLINK(&ipb_free);
+ spin_unlock(&ipb_free.lock);
+
ipbcfg.ln = 0;
if (ipbuf) {
kfree(ipbuf);
ipbuf = NULL;
}
+ for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+ dsp_mem_disable((void *)daram_base);
+ }
+ ipbuf_sys_hold_mem_active = 0;
}
-/*
- * ipbuf_config() is called by mailbox workqueue
- */
-int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr)
+int ipbuf_config(unsigned short ln, unsigned short lsz, void *base)
{
- void *base;
unsigned long lsz_byte = ((unsigned long)lsz) << 1;
size_t size;
int ret = 0;
int i;
- spin_lock(&ipb_free.lock);
- INIT_IPBLINK(&ipb_free);
- spin_unlock(&ipb_free.lock);
-
/*
* global IPBUF
*/
- if (adr & 0x1) {
+ if (((unsigned long)base) & 0x3) {
printk(KERN_ERR
- "mbx: global ipbuf address (0x%08lx) is odd number!\n",
- adr);
+ "omapdsp: global ipbuf address(0x%p) is not "
+ "32-bit aligned!\n", base);
return -EINVAL;
}
size = lsz_byte * ln;
- if (adr + size > DSPSPACE_SIZE) {
- printk(KERN_ERR
- "mbx: ipbuf address (0x%08lx) and size (0x%08x) is "
- "illegal!\n", adr, size);
+ if (dsp_address_validate(base, size, "global ipbuf") < 0)
return -EINVAL;
- }
- base = dspword_to_virt(adr);
+
ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL);
if (ipbuf == NULL) {
- printk(KERN_ERR "mbx: memory allocation for ipbuf failed.\n");
+ printk(KERN_ERR
+ "omapdsp: memory allocation for ipbuf failed.\n");
return -ENOMEM;
}
for (i = 0; i < ln; i++) {
"omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
" @0x%p, size=0x%08lx\n", i, top, lsz_byte);
ret = -EINVAL;
+ goto free_out;
}
}
ipbcfg.ln = ln;
ipbcfg.lsz = lsz;
- ipbcfg.adr = adr;
+ ipbcfg.base = base;
ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
ipbcfg.cnt_full = 0;
printk(KERN_INFO
"omapdsp: IPBUF configuration\n"
" %d words * %d lines at 0x%p.\n",
- ipbcfg.lsz, ipbcfg.ln, dspword_to_virt(ipbcfg.adr));
+ ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
return ret;
+
+free_out:
+ kfree(ipbuf);
+ ipbuf = NULL;
+ return ret;
+}
+
+int ipbuf_sys_config(void *p, enum arm_dsp_dir dir)
+{
+ char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+ if (((unsigned long)p) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: system ipbuf(%s) address(0x%p) is "
+ "not 32-bit aligned!\n", dir_str, p);
+ return -1;
+ }
+ if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
+ "system ipbuf(%s)", dir_str) < 0)
+ return -1;
+ if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
+ printk(KERN_WARNING
+ "omapdsp: system ipbuf(%s) is placed in"
+ " DSP internal memory.\n"
+ " It will prevent DSP from idling.\n", dir_str);
+ ipbuf_sys_hold_mem_active++;
+ /*
+ * dsp_mem_enable() never fails because
+ * it has been already enabled in dspcfg process and
+ * this will just increment the usecount.
+ */
+ dsp_mem_enable((void *)daram_base);
+ }
+
+ if (dir == DIR_D2A)
+ ipbuf_sys_da = p;
+ else
+ ipbuf_sys_ad = p;
+
+ return 0;
+}
+
+int ipbuf_p_validate(void *p, enum arm_dsp_dir dir)
+{
+ char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+ if (((unsigned long)p) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: private ipbuf(%s) address(0x%p) is "
+ "not 32-bit aligned!\n", dir_str, p);
+ return -1;
+ }
+ return dsp_address_validate(p, sizeof(struct ipbuf_p),
+ "private ipbuf(%s)", dir_str);
}
/*
{
unsigned short bid;
- if (ipblink_empty(&ipb_free)) {
- /* FIXME: wait on queue when not available. */
+ if (dsp_mem_enable_ipbuf() < 0)
return OMAP_DSP_BID_NULL;
- }
- /*
- * FIXME: dsp_enable_dspmem!
- */
spin_lock(&ipb_free.lock);
+
+ if (ipblink_empty(&ipb_free)) {
+ /* FIXME: wait on queue when not available. */
+ bid = OMAP_DSP_BID_NULL;
+ goto out;
+ }
bid = ipb_free.top;
ipbuf[bid]->la = tid; /* lock */
ipblink_del_top(&ipb_free, ipbuf);
+out:
spin_unlock(&ipb_free.lock);
+ dsp_mem_disable_ipbuf();
return bid;
}
static int try_yld(unsigned short bid)
{
- struct mbcmd mb;
int status;
ipbuf[bid]->sa = OMAP_DSP_TID_ANON;
- mbcmd_set(mb, MBCMD(BKYLD), 0, bid);
- status = dsp_mbsend(&mb);
+ status = dsp_mbsend(MBCMD(BKYLD), 0, bid);
if (status < 0) {
/* DSP is busy and ARM keeps this line. */
release_ipbuf(bid);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/17: DSP Gateway version 3.2
+ * 2005/05/17: DSP Gateway version 3.3
*/
struct ipbuf {
struct ipbuf_sys {
unsigned short s; /* sync word */
- unsigned short d[15]; /* data */
+ unsigned short d[31]; /* data */
};
struct ipbcfg {
unsigned short ln;
unsigned short lsz;
- unsigned long adr;
+ void *base;
unsigned short bsycnt;
unsigned long cnt_full; /* count of IPBFULL error */
};
enable_irq(INT_D2A_MB1); \
} while(0)
-#define dsp_mem_enable_ipbuf() dsp_mem_enable(dspword_to_virt(ipbcfg.adr))
-#define dsp_mem_disable_ipbuf() dsp_mem_disable(dspword_to_virt(ipbcfg.adr))
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base)
struct ipblink {
spinlock_t lock;
#define INIT_IPBLINK(link) \
do { \
+ spin_lock_init(&(link)->lock); \
(link)->top = OMAP_DSP_BID_NULL; \
(link)->tail = OMAP_DSP_BID_NULL; \
} while(0)
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/17: DSP Gateway version 3.2
+ * 2005/05/18: DSP Gateway version 3.3
*/
#include <linux/module.h>
(cmd_l == EID(BADTCTL)) ? "BADTCTL":
(cmd_l == EID(BADPARAM)) ? "BADPARAM":
(cmd_l == EID(FATAL)) ? "FATAL":
+ (cmd_l == EID(WDT)) ? "WDT":
(cmd_l == EID(NOMEM)) ? "NOMEM":
(cmd_l == EID(NORES)) ? "NORES":
(cmd_l == EID(IPBFULL)) ? "IPBFULL":
unsigned long jiffies;
unsigned short cmd;
unsigned short data;
- enum mblog_dir dir;
+ enum arm_dsp_dir dir;
};
static struct {
struct mblogent ent[MBLOG_DEPTH];
} mblog;
-void mblog_add(struct mbcmd *mb, enum mblog_dir dir)
+void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir)
{
struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
struct mblogent *ent;
if (mblog.cnt < 0xffffffff)
mblog.cnt++;
switch (dir) {
- case MBLOG_DIR_AD:
+ case DIR_A2D:
if (mblog.cnt_ad < 0xffffffff)
mblog.cnt_ad++;
break;
- case MBLOG_DIR_DA:
+ case DIR_D2A:
if (mblog.cnt_da < 0xffffffff)
mblog.cnt_da++;
break;
const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h];
len += sprintf(buf + len,
- (ent->dir == MBLOG_DIR_AD) ?
+ (ent->dir == DIR_A2D) ?
"%08lx %d %04x %04x ":
"%08lx %d %04x %04x ",
ent->jiffies, mb.sw.seq, ent->cmd, ent->data);
static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
-void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir)
+void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir)
{
const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
char *dir_str;
char *subname;
- dir_str = (dir == MBLOG_DIR_AD) ? "sending" : "receiving";
+ dir_str = (dir == DIR_A2D) ? "sending" : "receiving";
switch (ci->cmd_l_type) {
case CMD_L_TYPE_SUBCMD:
if ((subname = subcmd_name(mb)) == NULL)
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/11/22: DSP Gateway version 3.2
+ * 2004/11/22: DSP Gateway version 3.3
*/
struct proc_list {
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/02/22: DSP Gateway version 3.2
+ * 2005/07/26: DSP Gateway version 3.3
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include "fifo.h"
#include "proclist.h"
+#define is_aligned(adr,align) (!((adr)&((align)-1)))
+
/*
- * device state machine
+ * taskdev.state: device state machine
* NOTASK: task is not attached.
* ATTACHED: task is attached.
* GARBAGE: task is detached. waiting for all processes to close this device.
* ADDREQ: requesting for tadd
* DELREQ: requesting for tdel. no process is opening this device.
- * KILLREQ: requesting for tkill.
* ADDFAIL: tadd failed.
+ * ADDING: tadd in process.
+ * DELING: tdel in process.
+ * KILLING: tkill in process.
*/
+#define devstate_name(stat) (\
+ ((stat) & OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
+ ((stat) & OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\
+ ((stat) & OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\
+ ((stat) & OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\
+ ((stat) & OMAP_DSP_DEVSTATE_ADDING) ? "ADDING" :\
+ ((stat) & OMAP_DSP_DEVSTATE_DELING) ? "DELING" :\
+ ((stat) & OMAP_DSP_DEVSTATE_KILLING) ? "KILLING" :\
+ "unknown")
struct taskdev {
struct bus_type *bus;
static void taskdev_delete(unsigned char minor);
static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
static void taskdev_detach_task(struct taskdev *dev);
+static int dsp_tdel_bh(unsigned char minor, unsigned short type);
static ssize_t devname_show(struct device *d, struct device_attribute *attr,
char *buf);
{
unsigned short ttyp;
struct mbcmd mb;
+ int ret;
- dsptask[tid] = task;
task->tid = tid;
+ dsptask[tid] = task;
/* TCFG request */
task->state = TASK_STATE_CFGREQ;
- if (down_interruptible(&cfg_sem))
- return -ERESTARTSYS;
+ if (down_interruptible(&cfg_sem)) {
+ ret = -ERESTARTSYS;
+ goto fail_out;
+ }
cfg_cmd = MBCMD(TCFG);
mbcmd_set(mb, MBCMD(TCFG), tid, 0);
- dsp_mbsend_and_wait(&mb, &cfg_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
cfg_cmd = 0;
up(&cfg_sem);
if (task->state != TASK_STATE_READY) {
printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail_out;
}
if (strlen(task->name) <= 1)
ttyp = task->ttyp;
+ /*
+ * task info sanity check
+ */
+
/* task type check */
if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
- printk(KERN_ERR "mbx: illegal task type(0x%04x), tid=%d\n",
+ printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
tid, ttyp);
+ ret = -EINVAL;
+ goto fail_out;
}
/* private buffer address check */
- if (sndtyp_pvt(ttyp)) {
- void *p = task->rcvdt.bk.ipbuf_pvt_r;
-
- if ((unsigned long)p & 0x1) {
- printk(KERN_ERR
- "mbx: private ipbuf (DSP->ARM) address (0x%p) "
- "is odd number!\n", p);
- return -EINVAL;
- }
+ if (sndtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->rcvdt.bk.ipbuf_pvt_r, DIR_D2A) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
}
-
- if (rcvtyp_pvt(ttyp)) {
- void *p = task->ipbuf_pvt_w;
-
- if ((unsigned long)p & 0x1) {
- printk(KERN_ERR
- "mbx: private ipbuf (ARM->DSP) address (0x%p) "
- "is odd number!\n", p);
- return -EINVAL;
- }
+ if (rcvtyp_pvt(ttyp) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ /* mmap buffer configuration check */
+ if ((task->map_length > 0) &&
+ ((!is_aligned((unsigned long)task->map_base, PAGE_SIZE)) ||
+ (!is_aligned(task->map_length, PAGE_SIZE)) ||
+ (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+ printk(KERN_ERR
+ "omapdsp: illegal mmap buffer address(0x%p) or "
+ "length(0x%x).\n"
+ " It needs to be page-aligned and located at "
+ "external memory.\n",
+ task->map_base, task->map_length);
+ ret = -EINVAL;
+ goto fail_out;
}
+ /*
+ * initialization
+ */
+
/* read initialization */
if (sndtyp_wd(ttyp)) {
/* word */
printk(KERN_ERR
"omapdsp: unable to allocate receive buffer. "
"(%d bytes for %s)\n", fifosz, task->name);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail_out;
}
} else {
/* block */
- spin_lock_init(&task->rcvdt.bk.link.lock);
INIT_IPBLINK(&task->rcvdt.bk.link);
task->rcvdt.bk.rp = 0;
}
ipbcfg.lsz*2; /* passive block */
return 0;
+
+fail_out:
+ dsptask[tid] = NULL;
+ return ret;
}
static void dsp_task_init(struct dsptask *task)
{
- struct mbcmd mb;
-
- mbcmd_set(mb, MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
- dsp_mbsend(&mb);
+ dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
}
int dsp_task_config_all(unsigned char n)
for (minor = 0; minor < TASKDEV_MAX; minor++) {
dev = taskdev[minor];
- if (dev &&
- ((dev->usecount > 0) ||
- (dev->state == OMAP_DSP_DEVSTATE_ADDREQ) ||
- (dev->state == OMAP_DSP_DEVSTATE_DELREQ)))
+ if (dev == NULL)
+ continue;
+ if (dev->usecount > 0) {
+ printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+ dev->name, dev->usecount);
return 1;
+ }
+/*
+ if ((dev->state & (OMAP_DSP_DEVSTATE_ADDREQ |
+ OMAP_DSP_DEVSTATE_DELREQ)) {
+*/
+ if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ) {
+ printk("dsp_taskmod_busy(): %s is in %s\n",
+ dev->name, devstate_name(dev->state));
+ return 1;
+ }
}
return 0;
}
ret = -ERESTARTSYS;
goto up_out;
}
- base = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al));
- src = base + rcvdt->rp;
+ base = MKVIRT(ipbp->ah, ipbp->al);
+ bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+ if (dsp_address_validate(base, bkcnt,
+ "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -ERESTARTSYS;
+ goto pv_out1;
+ }
if (dsp_mem_enable(base) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
- bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+ src = base + rcvdt->rp;
if (bkcnt > count) {
if (copy_to_user_dsp(buf, src, count)) {
ret = -EFAULT;
devstate_unlock(dev);
mbcmd_set(mb, MBCMD(WDREQ), tid, 0);
- dsp_mbsend_and_wait(&mb, &dev->read_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
devstate_unlock(dev);
mbcmd_set(mb, MBCMD(BKREQ), tid, count/2);
- dsp_mbsend_and_wait(&mb, &dev->read_wait_q);
+ dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
ret = -ERESTARTSYS;
goto unlock_out;
}
- src = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al));
+ src = MKVIRT(ipbp->ah, ipbp->al);
+ rcvcnt = ((unsigned long)ipbp->c) * 2;
+ if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+ dev->task->name) < 0) {
+ ret = -ERESTARTSYS;
+ goto pv_out1;
+ }
if (dsp_mem_enable(src) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
- rcvcnt = ((unsigned long)ipbp->c) * 2;
if (count > rcvcnt)
count = rcvcnt;
if (copy_to_user_dsp(buf, src, count)) {
{
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
struct taskdev *dev = taskdev[minor];
- struct mbcmd mb;
unsigned short wd;
int have_devstate_lock = 0;
int ret = 0;
goto up_out;
}
- mbcmd_set(mb, MBCMD(WDSND), dev->task->tid, wd);
spin_lock(&dev->task->wsz_lock);
- if (dsp_mbsend(&mb) < 0) {
+ if (dsp_mbsend(MBCMD(WDSND), dev->task->tid, wd) < 0) {
spin_unlock(&dev->task->wsz_lock);
goto up_out;
}
{
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
struct taskdev *dev = taskdev[minor];
- struct mbcmd mb;
int have_devstate_lock = 0;
int ret = 0;
ret = -ERESTARTSYS;
goto up_out;
}
- dst = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al));
+ dst = MKVIRT(ipbp->ah, ipbp->al);
+ if (dsp_address_validate(dst, count, "task %s write buffer",
+ dev->task->name) < 0) {
+ ret = -ERESTARTSYS;
+ goto pv_out1;
+ }
if (dsp_mem_enable(dst) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
ipbp->c = count/2;
ipbp->s = dev->task->tid;
- mbcmd_set(mb, MBCMD(BKSNDP), dev->task->tid, 0);
spin_lock(&dev->task->wsz_lock);
- if (dsp_mbsend(&mb) == 0) {
+ if (dsp_mbsend(MBCMD(BKSNDP), dev->task->tid, 0) == 0) {
if (rcvtyp_acv(dev->task->ttyp))
dev->task->wsz = 0;
ret = count;
}
ipbp->c = count/2;
ipbp->sa = dev->task->tid;
- mbcmd_set(mb, MBCMD(BKSND), dev->task->tid, bid);
spin_lock(&dev->task->wsz_lock);
- if (dsp_mbsend(&mb) == 0) {
+ if (dsp_mbsend(MBCMD(BKSND), dev->task->tid, bid) == 0) {
if (rcvtyp_acv(dev->task->ttyp))
dev->task->wsz = 0;
ret = count;
* reserved for backward compatibility
* user-defined TCTL commands: no arg, non-interactive
*/
+ printk(KERN_WARNING "omapdsp: "
+ "TCTL commands in 0x0080 - 0x0100 are obsolete.\n"
+ "they won't be supported in the future.\n");
mbargc = 0;
interactive = 0;
} else if (cmd < 0x8000) {
dev->task->tctl_stat = -ERESTARTSYS;
devstate_unlock(dev);
- dsp_mbsend_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q);
+ dsp_mbcmd_send_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
goto up_out;
goto unlock_out;
}
} else {
- dsp_mbsend_exarg(&mb, mbargp);
+ dsp_mbcmd_send_exarg(&mb, mbargp);
ret = 0;
}
return ret;
}
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
+ task = dev->task;
+ exmap_use(task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+ struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+ struct dsptask *task;
+ size_t len = vma->vm_end - vma->vm_start;
+
+ BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
+ task = dev->task;
+ exmap_unuse(task->map_base, len);
+}
+
/**
* On demand page allocation is not allowed. The mapping area is defined by
* corresponding DSP tasks.
*/
-static struct page *dsp_task_nopage_mmap(struct vm_area_struct *vma,
+static struct page *dsp_task_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
return NOPAGE_SIGBUS;
}
static struct vm_operations_struct dsp_task_vm_ops = {
- .nopage = dsp_task_nopage_mmap,
+ .open = dsp_task_mmap_open,
+ .close = dsp_task_mmap_close,
+ .nopage = dsp_task_mmap_nopage,
};
static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
return -ERESTARTSYS;
task = dev->task;
- if (task->map_length == 0) {
- printk(KERN_ERR
- "omapdsp: task %s doesn't have mmap buffer.\n",
- task->name);
- ret = -EINVAL;
- goto unlock_out;
- }
- if (is_dsp_internal_mem(task->map_base)) {
- printk(KERN_ERR
- "omapdsp: task %s: map_base = %p\n"
- " DARAM/SARAM can't be used as mmap buffer.\n",
- task->name, task->map_base);
- ret = -EINVAL;
- goto unlock_out;
- }
/*
* Don't swap this area out
} while (req_len);
vma->vm_ops = &dsp_task_vm_ops;
+ vma->vm_private_data = dev;
+ exmap_use(task->map_base, vma->vm_end - vma->vm_start);
+
unlock_out:
devstate_unlock(dev);
return ret;
struct taskdev *dev;
int ret = 0;
- if (minor >= TASKDEV_MAX)
- return -ENODEV;
- dev = taskdev[minor];
- if (dev == NULL)
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
return -ENODEV;
-
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK |
OMAP_DSP_DEVSTATE_ATTACHED) < 0)
return -ERESTARTSYS;
}
#endif
- if (dev->state == OMAP_DSP_DEVSTATE_NOTASK) {
+ if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) {
dev->state = OMAP_DSP_DEVSTATE_ADDREQ;
/* wake up twch daemon for tadd */
dsp_twch_touch();
devstate_unlock(dev);
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED |
- OMAP_DSP_DEVSTATE_ADDFAIL) < 0)
+ OMAP_DSP_DEVSTATE_ADDFAIL) < 0) {
+ spin_lock(&dev->state_lock);
+ if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ)
+ dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+ spin_unlock(&dev->state_lock);
return -ERESTARTSYS;
- if (dev->state == OMAP_DSP_DEVSTATE_ADDFAIL) {
+ }
+ if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) {
printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
dev->name);
ret = -EBUSY;
/* state_lock covers usecount, proc_list as well. */
spin_lock(&dev->state_lock);
- /* state can be ATTACHED, KILLREQ or GARBAGE here. */
- switch (dev->state) {
+ /* state can be ATTACHED, KILLING or GARBAGE here. */
+ switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
- case OMAP_DSP_DEVSTATE_KILLREQ:
+ case OMAP_DSP_DEVSTATE_KILLING:
dev->usecount--;
break;
static int dsp_rmdev_minor(unsigned char minor)
{
struct taskdev *dev = taskdev[minor];
- struct dsptask *task = dev->task;
spin_lock(&dev->state_lock);
- switch (dev->state) {
+ switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
case OMAP_DSP_DEVSTATE_NOTASK:
/* fine */
siginfo_t info;
struct proc_list *pl;
+ dev->state = OMAP_DSP_DEVSTATE_KILLING;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = SI_KERNEL;
list_for_each_entry(pl, &dev->proc_list, list_head) {
send_sig_info(SIGBUS, &info, pl->tsk);
}
- taskdev_detach_task(dev);
- dsp_task_unconfig(task);
- kfree(task);
- dev->state = OMAP_DSP_DEVSTATE_GARBAGE;
+ spin_unlock(&dev->state_lock);
+ dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+ goto invalidate;
}
- break;
case OMAP_DSP_DEVSTATE_ADDREQ:
/* open() is waiting. drain it. */
wake_up_interruptible_all(&dev->state_wait_q);
break;
- case OMAP_DSP_DEVSTATE_KILLREQ:
+ case OMAP_DSP_DEVSTATE_ADDING:
+ case OMAP_DSP_DEVSTATE_DELING:
+ case OMAP_DSP_DEVSTATE_KILLING:
case OMAP_DSP_DEVSTATE_GARBAGE:
case OMAP_DSP_DEVSTATE_ADDFAIL:
/* transient state. wait for a moment. */
spin_unlock(&dev->state_lock);
+invalidate:
/* wait for some time and hope the state is settled */
devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ);
- if (dev->state != OMAP_DSP_DEVSTATE_NOTASK) {
+ if (!(dev->state & OMAP_DSP_DEVSTATE_NOTASK)) {
printk(KERN_WARNING
- "omapdsp: illegal device state on rmdev %s.\n",
- dev->name);
+ "omapdsp: illegal device state (%s) on rmdev %s.\n",
+ devstate_name(dev->state), dev->name);
}
dev->state = OMAP_DSP_DEVSTATE_INVALID;
devstate_unlock(dev);
.ioctl = dsp_task_ioctl,
.open = dsp_task_open,
.release = dsp_task_release,
- .mmap = dsp_task_mmap,
};
static void dsptask_dev_release(struct device *dev)
device_create_file(&dev->dev, &dev_attr_proc_list);
class_device_create(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor),
NULL, "dsptask%d", minor);
- devfs_mk_cdev(MKDEV(OMAP_DSP_TASK_MAJOR, minor),
- S_IFCHR | S_IRUGO | S_IWUGO, "dsptask%d", minor);
init_waitqueue_head(&dev->state_wait_q);
spin_lock_init(&dev->state_lock);
device_remove_file(&dev->dev, &dev_attr_devname);
device_remove_file(&dev->dev, &dev_attr_devstate);
device_remove_file(&dev->dev, &dev_attr_proc_list);
-
class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
- devfs_remove("dsptask%d", minor);
device_unregister(&dev->dev);
proc_list_flush(&dev->proc_list);
taskdev[minor] = NULL;
dev->fops.write =
rcvtyp_wd(ttyp) ? dsp_task_write_wd:
/* rcvbyp_bk */ dsp_task_write_bk;
+ if (task->map_length)
+ dev->fops.mmap = dsp_task_mmap;
device_create_file(&dev->dev, &dev_attr_taskname);
device_create_file(&dev->dev, &dev_attr_ttyp);
struct dsptask *task;
struct mbcmd mb;
struct mb_exarg arg;
- unsigned char tid;
+ unsigned char tid, tid_response;
unsigned short argv[2];
int ret = minor;
"omapdsp: no task device with minor %d\n", minor);
return -EINVAL;
}
- /*
- * we don't need to lock state_lock because
- * only tadd is allowed when devstate is ADDREQ.
- */
- if (dev->state != OMAP_DSP_DEVSTATE_ADDREQ) {
+
+ spin_lock(&dev->state_lock);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) {
printk(KERN_ERR
- "omapdsp: taskdev %s is not requesting for tadd.\n",
- dev->name);
+ "omapdsp: taskdev %s is not requesting for tadd. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ spin_unlock(&dev->state_lock);
return -EINVAL;
}
+ dev->state = OMAP_DSP_DEVSTATE_ADDING;
+ spin_unlock(&dev->state_lock);
if (adr == OMAP_DSP_TADD_ABORTADR) {
/* aborting tadd intentionally */
arg.argc = 2;
arg.argv = argv;
- dsp_mbsend_and_wait_exarg(&mb, &arg, &cfg_wait_q);
+ dsp_mem_sync_inc();
+ dsp_mbcmd_send_and_wait_exarg(&mb, &arg, &cfg_wait_q);
tid = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON;
}
if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
- goto fail_out;
+ goto del_out;
}
memset(task, 0, sizeof(struct dsptask));
"omapdsp: task name (%s) doesn't match with "
"device name (%s).\n", task->name, dev->name);
ret = -EINVAL;
- dev->state = OMAP_DSP_DEVSTATE_DELREQ;
- dsp_twch_touch();
- return -EINVAL;
+ goto free_out;
}
dsp_task_init(task);
free_out:
kfree(task);
+
+del_out:
+ printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+ dev->state = OMAP_DSP_DEVSTATE_DELING;
+
+ if (down_interruptible(&cfg_sem)) {
+ printk(KERN_ERR "omapdsp: aborting tdel process. "
+ "DSP side could be corrupted.\n");
+ goto fail_out;
+ }
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = MBCMD(TDEL);
+ mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = OMAP_DSP_TID_ANON;
+ cfg_cmd = 0;
+ up(&cfg_sem);
+
+ if (tid_response != tid)
+ printk(KERN_ERR "omapdsp: tdel failed. "
+ "DSP side could be corrupted.\n");
+
fail_out:
dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
wake_up_interruptible_all(&dev->state_wait_q);
int dsp_tdel(unsigned char minor)
{
struct taskdev *dev;
- struct dsptask *task;
- struct mbcmd mb;
- unsigned char tid, tid_response;
- int ret = minor;
if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
printk(KERN_ERR
"omapdsp: no task device with minor %d\n", minor);
return -EINVAL;
}
- /*
- * we don't need to lock state_lock because
- * only tdel is allowed when devstate is DELREQ.
- */
- if (dev->state != OMAP_DSP_DEVSTATE_DELREQ) {
+ spin_lock(&dev->state_lock);
+ if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) {
printk(KERN_ERR
- "omapdsp: taskdev %s is not requesting for tdel.\n",
- dev->name);
+ "omapdsp: taskdev %s is not requesting for tdel. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ spin_unlock(&dev->state_lock);
return -EINVAL;
}
+ dev->state = OMAP_DSP_DEVSTATE_DELING;
+ spin_unlock(&dev->state_lock);
- task = dev->task;
- tid = task->tid;
- if (down_interruptible(&cfg_sem)) {
- return -ERESTARTSYS;
- }
- cfg_tid = OMAP_DSP_TID_ANON;
- cfg_cmd = MBCMD(TDEL);
- mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_SAFE);
- dsp_mbsend_and_wait(&mb, &cfg_wait_q);
- tid_response = cfg_tid;
- cfg_tid = OMAP_DSP_TID_ANON;
- cfg_cmd = 0;
- up(&cfg_sem);
-
- taskdev_detach_task(dev);
- dsp_task_unconfig(task);
- kfree(task);
- dev->state = OMAP_DSP_DEVSTATE_NOTASK;
- wake_up_interruptible_all(&dev->state_wait_q);
-
- if (tid_response != tid) {
- printk(KERN_ERR "omapdsp: tdel failed!\n");
- ret = -EINVAL;
- }
-
- return ret;
+ return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE);
}
int dsp_tkill(unsigned char minor)
{
struct taskdev *dev;
- struct dsptask *task;
- struct mbcmd mb;
- unsigned char tid, tid_response;
siginfo_t info;
struct proc_list *pl;
- int ret = minor;
if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
printk(KERN_ERR
return -EINVAL;
}
spin_lock(&dev->state_lock);
- if (dev->state != OMAP_DSP_DEVSTATE_ATTACHED) {
+ if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) {
printk(KERN_ERR
"omapdsp: task has not been attached for taskdev %s\n",
dev->name);
spin_unlock(&dev->state_lock);
return -EINVAL;
}
- dev->state = OMAP_DSP_DEVSTATE_KILLREQ;
+ dev->state = OMAP_DSP_DEVSTATE_KILLING;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = SI_KERNEL;
}
spin_unlock(&dev->state_lock);
+ return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+}
+
+static int dsp_tdel_bh(unsigned char minor, unsigned short type)
+{
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ struct mbcmd mb;
+ unsigned char tid, tid_response;
+ int ret = minor;
+
task = dev->task;
tid = task->tid;
if (down_interruptible(&cfg_sem)) {
- tid_response = OMAP_DSP_TID_ANON;
- ret = -ERESTARTSYS;
- goto detach_out;
+ if (type == OMAP_DSP_MBCMD_TDEL_SAFE) {
+ dev->state = OMAP_DSP_DEVSTATE_DELREQ;
+ return -ERESTARTSYS;
+ } else {
+ tid_response = OMAP_DSP_TID_ANON;
+ ret = -ERESTARTSYS;
+ goto detach_out;
+ }
}
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = MBCMD(TDEL);
- mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL);
- dsp_mbsend_and_wait(&mb, &cfg_wait_q);
+ mbcmd_set(mb, MBCMD(TDEL), tid, type);
+ dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
tid_response = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = 0;
dsp_task_unconfig(task);
kfree(task);
- if (tid_response != tid)
- printk(KERN_ERR "omapdsp: tkill failed!\n");
-
+ if (tid_response != tid) {
+ printk(KERN_ERR "omapdsp: %s failed!\n",
+ (type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill");
+ ret = -EINVAL;
+ }
spin_lock(&dev->state_lock);
dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE :
OMAP_DSP_DEVSTATE_NOTASK;
/*
* state inquiry
*/
-long taskdev_state(unsigned char minor)
+long taskdev_state_stale(unsigned char minor)
{
- return taskdev[minor] ? taskdev[minor]->state :
- OMAP_DSP_DEVSTATE_NOTASK;
+ if (taskdev[minor]) {
+ long state = taskdev[minor]->state;
+ taskdev[minor]->state |= OMAP_DSP_DEVSTATE_STALE;
+ return state;
+ } else
+ return OMAP_DSP_DEVSTATE_NOTASK;
}
/*
{
unsigned char tid = mb->cmd_l;
struct dsptask *task = dsptask[tid];
- unsigned long tmp_ipbp_r, tmp_ipbp_w;
- unsigned long tmp_mapstart, tmp_maplen;
- unsigned long tmp_tnm;
unsigned short *tnm;
volatile unsigned short *buf;
int i;
if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n");
- return;
+ goto out;
}
/*
* read configuration data on system IPBUF
*/
buf = ipbuf_sys_da->d;
- task->ttyp = buf[0];
- tmp_ipbp_r = MKLONG(buf[1], buf[2]);
- tmp_ipbp_w = MKLONG(buf[3], buf[4]);
- tmp_mapstart = MKLONG(buf[5], buf[6]);
- tmp_maplen = MKLONG(buf[7], buf[8]);
- tmp_tnm = MKLONG(buf[9], buf[10]);
-
- task->rcvdt.bk.ipbuf_pvt_r = dspword_to_virt(tmp_ipbp_r);
- task->ipbuf_pvt_w = dspword_to_virt(tmp_ipbp_w);
- task->map_base = dspword_to_virt(tmp_mapstart);
- task->map_length = tmp_maplen << 1; /* word -> byte */
- tnm = dspword_to_virt(tmp_tnm);
+ task->ttyp = buf[0];
+ task->rcvdt.bk.ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+ task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+ task->map_base = MKVIRT(buf[5], buf[6]);
+ task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */
+ tnm = MKVIRT(buf[9], buf[10]);
+ release_ipbuf_pvt(ipbuf_sys_da);
+
+ /*
+ * copy task name string
+ */
+ if (dsp_address_validate(tnm, OMAP_DSP_TNM_LEN, "task name buffer") <0) {
+ task->name[0] = '\0';
+ goto out;
+ }
+
for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) {
/* avoiding byte access */
unsigned short tmp = tnm[i];
}
task->name[OMAP_DSP_TNM_LEN-1] = '\0';
- release_ipbuf_pvt(ipbuf_sys_da);
task->state = TASK_STATE_READY;
+out:
wake_up_interruptible(&cfg_wait_q);
}
spin_unlock(&task->dev->state_lock);
}
+static short *dbg_buf;
+static unsigned short dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
+ dbg_buf = NULL;
+ dbg_buf_sz = 0;
+ dbg_line_sz = 0;
+ dbg_rp = 0;
+ return 0;
+ }
+#endif
+
+ if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+ return -1;
+
+ if (lsz > sz) {
+ printk(KERN_ERR
+ "omapdsp: dbg_buf lsz (%d) is greater than its "
+ "buffer size (%d)\n", lsz, sz);
+ return -1;
+ }
+
+ dbg_buf = buf;
+ dbg_buf_sz = sz;
+ dbg_line_sz = lsz;
+ dbg_rp = 0;
+
+ return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+ dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbx1_dbg_old(struct mbcmd *mb);
+#endif
+
void mbx1_dbg(struct mbcmd *mb)
+{
+ unsigned char tid = mb->cmd_l;
+ int cnt = mb->data;
+ char s[80], *s_end = &s[79], *p;
+ unsigned short *src;
+ int i;
+
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
+ mbx1_dbg_old(mb);
+ return;
+ }
+#endif
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != OMAP_DSP_TID_ANON)) {
+ printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dbg_buf == NULL) {
+ printk(KERN_ERR "mbx: DBG command received, but "
+ "dbg_buf has not been configured yet.\n");
+ return;
+ }
+
+ if (dsp_mem_enable(dbg_buf) < 0)
+ return;
+
+ src = &dbg_buf[dbg_rp];
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ unsigned short tmp;
+ /*
+ * Be carefull that dbg_buf should not be read with
+ * 1-byte access since it might be placed in DARAM/SARAM
+ * and it can cause unexpected byteswap.
+ * For example,
+ * *(p++) = *(src++) & 0xff;
+ * causes 1-byte access!
+ */
+ tmp = *src++;
+ *(p++) = tmp & 0xff;
+ if (*(p-1) == '\n') {
+ *p = '\0';
+ printk(KERN_INFO "%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ printk(KERN_INFO "%s\n", s);
+ }
+ if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+ dbg_rp = 0;
+
+ dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbx1_dbg_old(struct mbcmd *mb)
{
unsigned char tid = mb->cmd_l;
char s[80], *s_end = &s[79], *p;
}
buf = ipbuf_sys_da->d;
cnt = buf[0];
- src = dspword_to_virt(MKLONG(buf[1], buf[2]));
+ src = MKVIRT(buf[1], buf[2]);
+ if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+ return;
+
+ if (dsp_mem_enable(src) < 0)
+ return;
+
p = s;
for (i = 0; i < cnt; i++) {
unsigned short tmp;
}
release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(src);
}
-
+#endif /* OLD_BINARY_SUPPORT */
/*
* sysfs files
return sprintf(buf, "%s\n", dev->name);
}
-#define devstate_name(stat) (\
- ((stat) == OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\
- ((stat) == OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
- ((stat) == OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\
- ((stat) == OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\
- ((stat) == OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\
- ((stat) == OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\
- ((stat) == OMAP_DSP_DEVSTATE_KILLREQ) ? "KILLREQ" :\
- ((stat) == OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\
- "unknown")
-
static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return -EINVAL;
}
dsp_task_class = class_create(THIS_MODULE, "dsptask");
- devfs_mk_dir("dsptask");
return 0;
}
void dsp_taskmod_exit(void)
{
- devfs_remove("dsptask");
class_destroy(dsp_task_class);
driver_unregister(&dsptask_driver);
bus_unregister(&dsptask_bus);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/12/01: DSP Gateway version 3.2
+ * 200%/05/16: DSP Gateway version 3.3
*/
#include <linux/module.h>
count = devcount * sizeof(long);
change_cnt = 0;
for (i = 0; i < devcount; i++) {
- taskstat[i] = taskdev_state(i);
+ /*
+ * once the device state is read, the 'STALE' bit will be set
+ * so that the Dynamic Loader can distinguish the new request
+ * from the old one.
+ */
+ taskstat[i] = taskdev_state_stale(i);
}
if (copy_to_user(buf, taskstat, count))
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/06/29: DSP Gateway version 3.2
+ * 2004/06/29: DSP Gateway version 3.3
*/
#include <linux/linkage.h>
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/06/29: DSP Gateway version 3.2
+ * 2004/06/29: DSP Gateway version 3.3
*/
#ifndef _OMAP_DSP_UACCESS_DSP_H
static void omap_mcbsp_dsp_request(void)
{
if (cpu_is_omap1510() || cpu_is_omap16xx()) {
- omap_dsp_request_idle();
+ omap_dsp_request_mem();
clk_use(mcbsp_dsp_ck);
clk_use(mcbsp_api_ck);
static void omap_mcbsp_dsp_free(void)
{
if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ omap_dsp_release_mem();
clk_unuse(mcbsp_dspxor_ck);
clk_unuse(mcbsp_dsp_ck);
clk_unuse(mcbsp_api_ck);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2005/01/17: DSP Gateway version 3.2
+ * 2005/06/01: DSP Gateway version 3.3
*/
#ifndef ASM_ARCH_DSP_H
#define OMAP_DSP_IOCTL_RESET 1
#define OMAP_DSP_IOCTL_RUN 2
#define OMAP_DSP_IOCTL_SETRSTVECT 3
-#define OMAP_DSP_IOCTL_IDLE 4
+#define OMAP_DSP_IOCTL_CPU_IDLE 4
#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5
#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6
#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7
#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8
+#define OMAP_DSP_IOCTL_GBL_IDLE 9
#define OMAP_DSP_IOCTL_DSPCFG 10
#define OMAP_DSP_IOCTL_DSPUNCFG 11
#define OMAP_DSP_IOCTL_TASKCNT 12
+#define OMAP_DSP_IOCTL_POLL 13
#define OMAP_DSP_IOCTL_REGMEMR 40
#define OMAP_DSP_IOCTL_REGMEMW 41
#define OMAP_DSP_IOCTL_REGIOR 42
#define OMAP_DSP_DEVSTATE_INVALID 0x00000008
#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100
#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200
-#define OMAP_DSP_DEVSTATE_KILLREQ 0x00000400
#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000
+#define OMAP_DSP_DEVSTATE_ADDING 0x00010000
+#define OMAP_DSP_DEVSTATE_DELING 0x00020000
+#define OMAP_DSP_DEVSTATE_KILLING 0x00040000
+#define OMAP_DSP_DEVSTATE_STATE_MASK 0x7fffffff
+#define OMAP_DSP_DEVSTATE_STALE 0x80000000
struct omap_dsp_taddinfo {
unsigned char minor;
unsigned short val[0];
};
-#define OMAP_DSP_MBPROT_REVISION 0x0018
+#define OMAP_DSP_MBPROT_REVISION 0x0019
#define OMAP_DSP_MBCMD_WDSND 0x10
#define OMAP_DSP_MBCMD_WDREQ 0x11
#define OMAP_DSP_MBCMD_BKREQP 0x25
#define OMAP_DSP_MBCMD_TCTL 0x30
#define OMAP_DSP_MBCMD_TCTLDATA 0x31
-#define OMAP_DSP_MBCMD_WDT 0x50
+#define OMAP_DSP_MBCMD_POLL 0x32
+#define OMAP_DSP_MBCMD_WDT 0x50 /* v3.3: obsolete */
#define OMAP_DSP_MBCMD_RUNLEVEL 0x51
#define OMAP_DSP_MBCMD_PM 0x52
#define OMAP_DSP_MBCMD_SUSPEND 0x53
#define OMAP_DSP_EID_NOMEM 0xc0
#define OMAP_DSP_EID_NORES 0xc1
#define OMAP_DSP_EID_IPBFULL 0xc2
+#define OMAP_DSP_EID_WDT 0xd0
#define OMAP_DSP_EID_TASKNOTRDY 0xe0
#define OMAP_DSP_EID_TASKBSY 0xe1
#define OMAP_DSP_EID_TASKERR 0xef
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 2004/09/22: DSP Gateway version 3.2
+ * 2005/06/03: DSP Gateway version 3.3
*/
#ifndef ASM_ARCH_DSP_COMMON_H
void omap_dsp_pm_suspend(void);
void omap_dsp_pm_resume(void);
-void omap_dsp_request_idle(void);
+void omap_dsp_request_mpui(void);
+void omap_dsp_release_mpui(void);
+int omap_dsp_request_mem(void);
+int omap_dsp_release_mem(void);
#endif /* ASM_ARCH_DSP_COMMON_H */