From: Tony Lindgren <tony@atomide.com>
To: linux-omap@vger.kernel.org, linux-omap-open-source@linux.omap.com
Cc: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Subject: Re: [PATCH 2/2] DSP: Move dspgateway to drivers/dsp/dspgateway
Date: Tue, 27 Nov 2007 21:20:08 -0800 [thread overview]
Message-ID: <20071128052005.GJ11825@atomide.com> (raw)
In-Reply-To: <20071128051811.GI11825@atomide.com>
[-- Attachment #1: Type: text/plain, Size: 56 bytes --]
This patch does the actual moving of the files.
Tony
[-- Attachment #2: 0002-DSP-Move-dspgateway-to-drivers-dsp-dspgateway.patch --]
[-- Type: text/x-diff, Size: 452102 bytes --]
>From c43c710df9b75494ce931f8e4b730a7f54d56d05 Mon Sep 17 00:00:00 2001
From: Tony Lindgren <tony@atomide.com>
Date: Tue, 27 Nov 2007 21:13:02 -0800
Subject: [PATCH] DSP: Move dspgateway to drivers/dsp/dspgateway
Move dspgateway to drivers/dsp/dspgateway
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/Kconfig | 1 +
arch/arm/mach-omap1/mmu.c | 6 +
arch/arm/mach-omap1/mmu.h | 7 -
arch/arm/mach-omap2/mmu.h | 6 +-
arch/arm/plat-omap/Kconfig | 2 -
arch/arm/plat-omap/Makefile | 3 -
arch/arm/plat-omap/dsp/Kconfig | 24 -
arch/arm/plat-omap/dsp/Makefile | 15 -
arch/arm/plat-omap/dsp/dsp.h | 391 -----
arch/arm/plat-omap/dsp/dsp_common.c | 627 -------
arch/arm/plat-omap/dsp/dsp_core.c | 663 -------
arch/arm/plat-omap/dsp/dsp_ctl.c | 1069 ------------
arch/arm/plat-omap/dsp/dsp_ctl_core.c | 132 --
arch/arm/plat-omap/dsp/dsp_mbcmd.h | 147 --
arch/arm/plat-omap/dsp/dsp_mem.c | 482 ------
arch/arm/plat-omap/dsp/error.c | 227 ---
arch/arm/plat-omap/dsp/hardware_dsp.h | 34 -
arch/arm/plat-omap/dsp/ipbuf.c | 353 ----
arch/arm/plat-omap/dsp/ipbuf.h | 193 ---
arch/arm/plat-omap/dsp/mblog.c | 280 ---
arch/arm/plat-omap/dsp/mmu.h | 140 --
arch/arm/plat-omap/dsp/omap1_dsp.h | 114 --
arch/arm/plat-omap/dsp/omap2_dsp.h | 95 -
arch/arm/plat-omap/dsp/proclist.h | 87 -
arch/arm/plat-omap/dsp/task.c | 3042 ---------------------------------
arch/arm/plat-omap/dsp/taskwatch.c | 163 --
arch/arm/plat-omap/dsp/uaccess_dsp.S | 77 -
arch/arm/plat-omap/dsp/uaccess_dsp.h | 176 --
drivers/Makefile | 1 +
drivers/dsp/dspgateway/Kconfig | 24 +
drivers/dsp/dspgateway/Makefile | 15 +
drivers/dsp/dspgateway/dsp.h | 391 +++++
drivers/dsp/dspgateway/dsp_common.c | 627 +++++++
drivers/dsp/dspgateway/dsp_core.c | 663 +++++++
drivers/dsp/dspgateway/dsp_ctl.c | 1069 ++++++++++++
drivers/dsp/dspgateway/dsp_ctl_core.c | 132 ++
drivers/dsp/dspgateway/dsp_mbcmd.h | 147 ++
drivers/dsp/dspgateway/dsp_mem.c | 484 ++++++
drivers/dsp/dspgateway/error.c | 227 +++
drivers/dsp/dspgateway/hardware_dsp.h | 34 +
drivers/dsp/dspgateway/ipbuf.c | 353 ++++
drivers/dsp/dspgateway/ipbuf.h | 193 +++
drivers/dsp/dspgateway/mblog.c | 280 +++
drivers/dsp/dspgateway/mmu.h | 140 ++
drivers/dsp/dspgateway/omap1_dsp.h | 114 ++
drivers/dsp/dspgateway/omap2_dsp.h | 95 +
drivers/dsp/dspgateway/proclist.h | 87 +
drivers/dsp/dspgateway/task.c | 3042 +++++++++++++++++++++++++++++++++
drivers/dsp/dspgateway/taskwatch.c | 163 ++
drivers/dsp/dspgateway/uaccess_dsp.S | 77 +
drivers/dsp/dspgateway/uaccess_dsp.h | 176 ++
include/asm-arm/arch-omap/mmu.h | 10 +
52 files changed, 8552 insertions(+), 8548 deletions(-)
delete mode 100644 arch/arm/plat-omap/dsp/Kconfig
delete mode 100644 arch/arm/plat-omap/dsp/Makefile
delete mode 100644 arch/arm/plat-omap/dsp/dsp.h
delete mode 100644 arch/arm/plat-omap/dsp/dsp_common.c
delete mode 100644 arch/arm/plat-omap/dsp/dsp_core.c
delete mode 100644 arch/arm/plat-omap/dsp/dsp_ctl.c
delete mode 100644 arch/arm/plat-omap/dsp/dsp_ctl_core.c
delete mode 100644 arch/arm/plat-omap/dsp/dsp_mbcmd.h
delete mode 100644 arch/arm/plat-omap/dsp/dsp_mem.c
delete mode 100644 arch/arm/plat-omap/dsp/error.c
delete mode 100644 arch/arm/plat-omap/dsp/hardware_dsp.h
delete mode 100644 arch/arm/plat-omap/dsp/ipbuf.c
delete mode 100644 arch/arm/plat-omap/dsp/ipbuf.h
delete mode 100644 arch/arm/plat-omap/dsp/mblog.c
delete mode 100644 arch/arm/plat-omap/dsp/mmu.h
delete mode 100644 arch/arm/plat-omap/dsp/omap1_dsp.h
delete mode 100644 arch/arm/plat-omap/dsp/omap2_dsp.h
delete mode 100644 arch/arm/plat-omap/dsp/proclist.h
delete mode 100644 arch/arm/plat-omap/dsp/task.c
delete mode 100644 arch/arm/plat-omap/dsp/taskwatch.c
delete mode 100644 arch/arm/plat-omap/dsp/uaccess_dsp.S
delete mode 100644 arch/arm/plat-omap/dsp/uaccess_dsp.h
create mode 100644 drivers/dsp/dspgateway/Kconfig
create mode 100644 drivers/dsp/dspgateway/Makefile
create mode 100644 drivers/dsp/dspgateway/dsp.h
create mode 100644 drivers/dsp/dspgateway/dsp_common.c
create mode 100644 drivers/dsp/dspgateway/dsp_core.c
create mode 100644 drivers/dsp/dspgateway/dsp_ctl.c
create mode 100644 drivers/dsp/dspgateway/dsp_ctl_core.c
create mode 100644 drivers/dsp/dspgateway/dsp_mbcmd.h
create mode 100644 drivers/dsp/dspgateway/dsp_mem.c
create mode 100644 drivers/dsp/dspgateway/error.c
create mode 100644 drivers/dsp/dspgateway/hardware_dsp.h
create mode 100644 drivers/dsp/dspgateway/ipbuf.c
create mode 100644 drivers/dsp/dspgateway/ipbuf.h
create mode 100644 drivers/dsp/dspgateway/mblog.c
create mode 100644 drivers/dsp/dspgateway/mmu.h
create mode 100644 drivers/dsp/dspgateway/omap1_dsp.h
create mode 100644 drivers/dsp/dspgateway/omap2_dsp.h
create mode 100644 drivers/dsp/dspgateway/proclist.h
create mode 100644 drivers/dsp/dspgateway/task.c
create mode 100644 drivers/dsp/dspgateway/taskwatch.c
create mode 100644 drivers/dsp/dspgateway/uaccess_dsp.S
create mode 100644 drivers/dsp/dspgateway/uaccess_dsp.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d589397..f468fee 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1081,6 +1081,7 @@ source "drivers/dma/Kconfig"
if ARCH_OMAP
source "drivers/cbus/Kconfig"
+source "drivers/dsp/dspgateway/Kconfig"
endif
endmenu
diff --git a/arch/arm/mach-omap1/mmu.c b/arch/arm/mach-omap1/mmu.c
index a254410..c7cb4ff 100644
--- a/arch/arm/mach-omap1/mmu.c
+++ b/arch/arm/mach-omap1/mmu.c
@@ -81,6 +81,12 @@ void dsp_mem_usecount_clear(void)
}
EXPORT_SYMBOL_GPL(dsp_mem_usecount_clear);
+void omap_mmu_itack(struct omap_mmu *mmu)
+{
+ omap_mmu_write_reg(mmu, OMAP_MMU_IT_ACK_IT_ACK, OMAP_MMU_IT_ACK);
+}
+EXPORT_SYMBOL(omap_mmu_itack);
+
static int omap1_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
{
int ret = 0;
diff --git a/arch/arm/mach-omap1/mmu.h b/arch/arm/mach-omap1/mmu.h
index 9ab2d99..521c3bf 100644
--- a/arch/arm/mach-omap1/mmu.h
+++ b/arch/arm/mach-omap1/mmu.h
@@ -95,8 +95,6 @@ do { \
(ent)->ap = OMAP_MMU_RAM_L_AP_FA; \
} while (0)
-extern struct omap_mmu_ops omap1_mmu_ops;
-
struct omap_mmu_tlb_entry {
unsigned long va;
unsigned long pa;
@@ -118,9 +116,4 @@ static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
__raw_writew(val, mmu->base + reg);
}
-static inline void omap_mmu_itack(struct omap_mmu *mmu)
-{
- omap_mmu_write_reg(mmu, OMAP_MMU_IT_ACK_IT_ACK, OMAP_MMU_IT_ACK);
-}
-
#endif /* __MACH_OMAP1_MMU_H */
diff --git a/arch/arm/mach-omap2/mmu.h b/arch/arm/mach-omap2/mmu.h
index 736932e..818ea8c 100644
--- a/arch/arm/mach-omap2/mmu.h
+++ b/arch/arm/mach-omap2/mmu.h
@@ -93,8 +93,6 @@ do { \
(ent)->mixed = 0; \
} while (0)
-extern struct omap_mmu_ops omap2_mmu_ops;
-
struct omap_mmu_tlb_entry {
unsigned long va;
unsigned long pa;
@@ -115,7 +113,5 @@ static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
{
__raw_writel(val, mmu->base + reg);
}
-static inline void omap_mmu_itack(struct omap_mmu *mmu)
-{
-}
+
#endif /* __MACH_OMAP2_MMU_H */
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index d1558df..3cb9545 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -211,8 +211,6 @@ config OMAP_SERIAL_WAKE
to data on the serial RX line. This allows you to wake the
system from serial console.
-source "arch/arm/plat-omap/dsp/Kconfig"
-
endmenu
endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 4eaef7e..c1ada8f 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -32,6 +32,3 @@ obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
-# DSP subsystem
-obj-y += dsp/
-obj-$(CONFIG_OMAP_DSP) += mailbox.o
diff --git a/arch/arm/plat-omap/dsp/Kconfig b/arch/arm/plat-omap/dsp/Kconfig
deleted file mode 100644
index 122164a..0000000
--- a/arch/arm/plat-omap/dsp/Kconfig
+++ /dev/null
@@ -1,24 +0,0 @@
-
-config OMAP_DSP
- tristate "OMAP DSP driver (DSP Gateway)"
- depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX
- select OMAP_MMU_FWK
- select OMAP_MBOX_FWK
- help
- This enables OMAP DSP driver, DSP Gateway.
-
-config OMAP_DSP_MBCMD_VERBOSE
- bool "Mailbox Command Verbose LOG"
- depends on OMAP_DSP
- help
- This enables kernel log output in the Mailbox command exchanges
- in the DSP Gateway driver.
-
-config OMAP_DSP_FBEXPORT
- bool "Framebuffer export to DSP"
- depends on OMAP_DSP && FB
- help
- This enables to map the frame buffer to DSP.
- By doing this, DSP can access the frame buffer directly without
- bothering ARM.
-
diff --git a/arch/arm/plat-omap/dsp/Makefile b/arch/arm/plat-omap/dsp/Makefile
deleted file mode 100644
index c7d86f3..0000000
--- a/arch/arm/plat-omap/dsp/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Makefile for the OMAP DSP driver.
-#
-
-# The target object and module list name.
-
-obj-y := dsp_common.o
-
-obj-$(CONFIG_OMAP_DSP) += dsp.o
-
-# Declare multi-part drivers
-
-dsp-objs := dsp_core.o ipbuf.o mblog.o task.o \
- dsp_ctl_core.o dsp_ctl.o taskwatch.o error.o dsp_mem.o \
- uaccess_dsp.o
diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h
deleted file mode 100644
index a7eee1d..0000000
--- a/arch/arm/plat-omap/dsp/dsp.h
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __PLAT_OMAP_DSP_DSP_H
-#define __PLAT_OMAP_DSP_DSP_H
-
-#include "hardware_dsp.h"
-#include <asm/arch/dsp_common.h>
-#include <asm/arch/mmu.h>
-
-
-#ifdef CONFIG_ARCH_OMAP2
-#include "../../mach-omap2/prm.h"
-#include "../../mach-omap2/prm_regbits_24xx.h"
-#include "../../mach-omap2/cm.h"
-#include "../../mach-omap2/cm_regbits_24xx.h"
-#endif
-
-/*
- * MAJOR device number: !! allocated arbitrary !!
- */
-#define OMAP_DSP_CTL_MAJOR 96
-#define OMAP_DSP_TASK_MAJOR 97
-
-#define OLD_BINARY_SUPPORT y
-
-#ifdef OLD_BINARY_SUPPORT
-#define MBREV_3_0 0x0017
-#define MBREV_3_2 0x0018
-#endif
-
-#define DSP_INIT_PAGE 0xfff000
-
-#ifdef CONFIG_ARCH_OMAP1
-/* idle program will be placed at IDLEPG_BASE. */
-#define IDLEPG_BASE 0xfffe00
-#define IDLEPG_SIZE 0x100
-#endif /* CONFIG_ARCH_OMAP1 */
-
-/* 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,
-};
-
-
-typedef int __bitwise arm_dsp_dir_t;
-#define DIR_A2D ((__force arm_dsp_dir_t) 1)
-#define DIR_D2A ((__force arm_dsp_dir_t) 2)
-
-enum cfgstat_e {
- CFGSTAT_CLEAN = 0,
- CFGSTAT_READY,
- CFGSTAT_SUSPEND,
- CFGSTAT_RESUME, /* request only */
- CFGSTAT_MAX
-};
-
-enum errcode_e {
- ERRCODE_WDT = 0,
- ERRCODE_MMU,
- ERRCODE_MAX
-};
-
-/* keep 2 entries for TID_FREE and TID_ANON */
-#define TASKDEV_MAX 254
-
-#define MK32(uw,lw) (((u32)(uw)) << 16 | (lw))
-#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
-#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
-
-struct sync_seq {
- u16 da_dsp;
- u16 da_arm;
- u16 ad_dsp;
- u16 ad_arm;
-};
-
-struct mem_sync_struct {
- struct sync_seq *DARAM;
- struct sync_seq *SARAM;
- struct sync_seq *SDRAM;
-};
-
-/* struct mbcmd and union mbcmd_hw must be compatible */
-struct mbcmd {
- u32 data:16;
- u32 cmd_l:8;
- u32 cmd_h:7;
- u32 seq:1;
-};
-
-#define MBCMD_INIT(h, l, d) { \
- .cmd_h = (h), \
- .cmd_l = (l), \
- .data = (d), \
- }
-
-struct mb_exarg {
- u8 tid;
- int argc;
- u16 *argv;
-};
-
-typedef u32 dsp_long_t; /* must have ability to carry TADD_ABORTADR */
-
-extern void dsp_mbox_start(void);
-extern void dsp_mbox_stop(void);
-extern int dsp_mbox_config(void *p);
-extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
-extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
- int recovery_flag);
-#define dsp_mbcmd_send(mb) __dsp_mbcmd_send_exarg((mb), NULL, 0)
-#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send_exarg((mb), (arg), 0)
-extern int dsp_mbcmd_send_and_wait_exarg(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_exarg((mb), NULL, (q))
-
-static inline int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
- struct mb_exarg *arg,
- int recovery_flag)
-{
- struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
- return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
-}
-#define mbcompose_send(cmd_h, cmd_l, data) \
- __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
-#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
- __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
-#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
- __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
-
-static inline int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
- u16 data,
- struct mb_exarg *arg,
- wait_queue_head_t *q)
-{
- struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
- return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
-}
-#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
- __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
- NULL, (q))
-#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
- __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
- (arg), (q))
-
-extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
-extern void ipbuf_start(void);
-extern void ipbuf_stop(void);
-extern int ipbuf_config(u16 ln, u16 lsz, void *base);
-extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
-extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
-extern struct ipbuf_head *get_free_ipbuf(u8 tid);
-extern void release_ipbuf(struct ipbuf_head *ipb_h);
-extern void balance_ipbuf(void);
-extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
-extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
-
-#define release_ipbuf_pvt(ipbuf_pvt) \
- do { \
- (ipbuf_pvt)->s = TID_FREE; \
- } while(0)
-
-extern int mbox_revision;
-
-extern int dsp_cfgstat_request(enum cfgstat_e st);
-extern enum cfgstat_e dsp_cfgstat_get_stat(void);
-extern int dsp_set_runlevel(u8 level);
-
-extern int dsp_task_config_all(u8 n);
-extern void dsp_task_unconfig_all(void);
-extern u8 dsp_task_count(void);
-extern int dsp_taskmod_busy(void);
-extern int dsp_mkdev(char *name);
-extern int dsp_rmdev(char *name);
-extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
-extern int dsp_tdel_minor(unsigned char minor);
-extern int dsp_tkill_minor(unsigned char minor);
-extern long taskdev_state_stale(unsigned char minor);
-extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
-extern void dsp_dbg_stop(void);
-
-extern int ipbuf_is_held(u8 tid, u16 bid);
-
-extern int 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, ...);
-#ifdef CONFIG_ARCH_OMAP1
-extern void dsp_mem_usecount_clear(void);
-#endif
-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);
-extern void dsp_twch_touch(void);
-
-extern void dsp_err_start(void);
-extern void dsp_err_stop(void);
-extern void dsp_err_set(enum errcode_e code, unsigned long arg);
-extern void dsp_err_clear(enum errcode_e code);
-extern int dsp_err_isset(enum errcode_e code);
-
-enum cmd_l_type_e {
- CMD_L_TYPE_NULL,
- CMD_L_TYPE_TID,
- CMD_L_TYPE_SUBCMD,
-};
-
-struct cmdinfo {
- char *name;
- enum cmd_l_type_e cmd_l_type;
- void (*handler)(struct mbcmd *mb);
-};
-
-extern const struct cmdinfo *cmdinfo[];
-
-#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
-extern char *subcmd_name(struct mbcmd *mb);
-
-extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
-
-extern struct omap_mmu dsp_mmu;
-
-#define dsp_mem_enable(addr) omap_mmu_mem_enable(&dsp_mmu, (addr))
-#define dsp_mem_disable(addr) omap_mmu_mem_disable(&dsp_mmu, (addr))
-
-#define DSPSPACE_SIZE 0x1000000
-
-#define omap_set_bit_regw(b,r) \
- do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
-#define omap_clr_bit_regw(b,r) \
- do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
-#define omap_set_bit_regl(b,r) \
- do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
-#define omap_clr_bit_regl(b,r) \
- do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
-#define omap_set_bits_regl(val,mask,r) \
- do { omap_writel((omap_readl(r) & ~(mask)) | (val), (r)); } while(0)
-
-#define dspword_to_virt(dw) ((void *)(dspmem_base + ((dw) << 1)))
-#define dspbyte_to_virt(db) ((void *)(dspmem_base + (db)))
-#define virt_to_dspword(va) \
- ((dsp_long_t)(((unsigned long)(va) - dspmem_base) >> 1))
-#define virt_to_dspbyte(va) \
- ((dsp_long_t)((unsigned long)(va) - dspmem_base))
-#define is_dsp_internal_mem(va) \
- (((unsigned long)(va) >= dspmem_base) && \
- ((unsigned long)(va) < dspmem_base + dspmem_size))
-#define is_dspbyte_internal_mem(db) ((db) < dspmem_size)
-#define is_dspword_internal_mem(dw) (((dw) << 1) < dspmem_size)
-
-#ifdef CONFIG_ARCH_OMAP1
-/*
- * MPUI byteswap/wordswap on/off
- * default setting: wordswap = all, byteswap = APIMEM only
- */
-#define mpui_wordswap_on() \
- omap_set_bits_regl(MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL_WORDSWAP_MASK, \
- MPUI_CTRL)
-
-#define mpui_wordswap_off() \
- omap_set_bits_regl(MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL_WORDSWAP_MASK, \
- MPUI_CTRL)
-
-#define mpui_byteswap_on() \
- omap_set_bits_regl(MPUI_CTRL_BYTESWAP_API, MPUI_CTRL_BYTESWAP_MASK, \
- MPUI_CTRL)
-
-#define mpui_byteswap_off() \
- omap_set_bits_regl(MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL_BYTESWAP_MASK, \
- 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() omap_clr_bit_regl(TC_ENDIANISM_EN, TC_ENDIANISM)
-
-/*
- * enable priority registers, EMIF, MPUI control logic
- */
-#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
-#define __dsp_disable() omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
-#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)
-#endif /* CONFIG_ARCH_OMAP1 */
-
-#ifdef CONFIG_ARCH_OMAP2
-/*
- * PRCM / IPI control logic
- *
- * REVISIT: these macros should probably be static inline functions
- */
-#define __dsp_core_enable() \
- do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
- & ~OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
-#define __dsp_core_disable() \
- do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
- | OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
-#define __dsp_per_enable() \
- do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
- & ~OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
-#define __dsp_per_disable() \
- do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
- | OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
-#endif /* CONFIG_ARCH_OMAP2 */
-
-#if defined(CONFIG_ARCH_OMAP1)
-extern struct clk *dsp_ck_handle;
-extern struct clk *api_ck_handle;
-#elif defined(CONFIG_ARCH_OMAP2)
-extern struct clk *dsp_fck_handle;
-extern struct clk *dsp_ick_handle;
-#endif
-extern dsp_long_t dspmem_base, dspmem_size,
- daram_base, daram_size,
- saram_base, saram_size;
-
-enum cpustat_e {
- CPUSTAT_RESET = 0,
-#ifdef CONFIG_ARCH_OMAP1
- CPUSTAT_GBL_IDLE,
- CPUSTAT_CPU_IDLE,
-#endif
- CPUSTAT_RUN,
- CPUSTAT_MAX
-};
-
-int dsp_set_rstvect(dsp_long_t adr);
-dsp_long_t dsp_get_rstvect(void);
-void dsp_set_idle_boot_base(dsp_long_t adr, size_t size);
-void dsp_reset_idle_boot_base(void);
-void dsp_cpustat_request(enum cpustat_e req);
-enum cpustat_e dsp_cpustat_get_stat(void);
-u16 dsp_cpustat_get_icrmask(void);
-void dsp_cpustat_set_icrmask(u16 mask);
-void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
-void dsp_unregister_mem_cb(void);
-
-#if defined(CONFIG_ARCH_OMAP1)
-#define command_dvfs_stop(m) (0)
-#define command_dvfs_start(m) (0)
-#elif defined(CONFIG_ARCH_OMAP2)
-#define command_dvfs_stop(m) \
- (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_STOP))
-#define command_dvfs_start(m) \
- (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_START))
-#endif
-
-extern struct omap_dsp *omap_dsp;
-
-extern int dsp_late_init(void);
-
-#endif /* __PLAT_OMAP_DSP_DSP_H */
diff --git a/arch/arm/plat-omap/dsp/dsp_common.c b/arch/arm/plat-omap/dsp/dsp_common.c
deleted file mode 100644
index 99be995..0000000
--- a/arch/arm/plat-omap/dsp/dsp_common.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/tlbflush.h>
-#include <asm/irq.h>
-#include <asm/arch/dsp_common.h>
-#include "dsp.h"
-
-#ifdef CONFIG_ARCH_OMAP1
-#include <asm/arch/tc.h>
-#endif
-
-#if defined(CONFIG_ARCH_OMAP1)
-#define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG)
-#endif
-
-struct omap_dsp *omap_dsp;
-
-#if defined(CONFIG_ARCH_OMAP1)
-struct clk *dsp_ck_handle;
-struct clk *api_ck_handle;
-#elif defined(CONFIG_ARCH_OMAP2)
-struct clk *dsp_fck_handle;
-struct clk *dsp_ick_handle;
-#endif
-dsp_long_t dspmem_base, dspmem_size,
- daram_base, daram_size,
- saram_base, saram_size;
-
-static struct cpustat {
- struct mutex lock;
- enum cpustat_e stat;
- enum cpustat_e req;
- u16 icrmask;
-#ifdef CONFIG_ARCH_OMAP1
- struct {
- int mpui;
- int mem;
- int mem_delayed;
- } usecount;
- int (*mem_req_cb)(void);
- void (*mem_rel_cb)(void);
-#endif
-} cpustat = {
- .stat = CPUSTAT_RESET,
- .icrmask = 0xffff,
-};
-
-int dsp_set_rstvect(dsp_long_t adr)
-{
- unsigned long *dst_adr;
-
- if (adr >= DSPSPACE_SIZE)
- return -EINVAL;
-
- dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
- /* word swap */
- *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
- /* fill 8 bytes! */
- *(dst_adr + 1) = 0;
- /* direct boot */
- dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
-
- return 0;
-}
-
-dsp_long_t dsp_get_rstvect(void)
-{
- unsigned long *dst_adr;
-
- dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
- return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
-}
-
-#ifdef CONFIG_ARCH_OMAP1
-static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
-{
- int i;
- u16 *src = (u16 *)src_c;
- int len_w;
-
- /* len must be multiple of 2. */
- if (len & 1)
- BUG();
-
- len_w = len / 2;
- for (i = 0; i < len_w; i++) {
- /* byte swap copy */
- *dst = ((*src & 0x00ff) << 8) |
- ((*src & 0xff00) >> 8);
- src++;
- dst++;
- }
-}
-
-/* program size must be multiple of 2 */
-#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 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 */ \
- 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 /* 0x20: nop */ \
-}
-
-/*
- * idle_boot base:
- * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
- * This value is used before DSP Gateway driver is initialized.
- * DSP Gateway driver will overwrite this value with other value,
- * to avoid confliction with the user program.
- */
-static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI;
-
-static void dsp_gbl_idle(void)
-{
- unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
-
- __dsp_reset();
- clk_enable(api_ck_handle);
-
-#if 0
- dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
-#endif
- simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
- GBL_IDLE_TEXT_SIZE);
- if (idle_boot_base == DSP_BOOT_ADR_MPUI)
- dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
- else
- dsp_set_rstvect(idle_boot_base);
-
- __dsp_run();
- udelay(100); /* to make things stable */
- clk_disable(api_ck_handle);
-}
-
-static void dsp_cpu_idle(void)
-{
- u16 icr_tmp;
- unsigned char icrh, icrl;
-
- __dsp_reset();
- clk_enable(api_ck_handle);
-
- /*
- * icr settings:
- * DMA should not sleep for DARAM/SARAM access
- * DPLL should not sleep while any other domain is active
- */
- icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL);
- icrh = icr_tmp >> 8;
- icrl = icr_tmp & 0xff;
- {
- 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),
- CPU_IDLE_TEXT_SIZE);
- }
- if (idle_boot_base == DSP_BOOT_ADR_MPUI)
- dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
- else
- dsp_set_rstvect(idle_boot_base);
- __dsp_run();
- udelay(100); /* to make things stable */
- clk_disable(api_ck_handle);
-}
-
-void dsp_set_idle_boot_base(dsp_long_t adr, size_t size)
-{
- if (adr == idle_boot_base)
- return;
- idle_boot_base = adr;
- if ((size < GBL_IDLE_TEXT_SIZE) ||
- (size < CPU_IDLE_TEXT_SIZE)) {
- printk(KERN_ERR
- "omapdsp: size for idle program is not enough!\n");
- BUG();
- }
-
- /* 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();
-}
-
-void dsp_reset_idle_boot_base(void)
-{
- idle_boot_base = DSP_BOOT_ADR_MPUI;
-}
-#else
-void dsp_reset_idle_boot_base(void) { }
-#endif /* CONFIG_ARCH_OMAP1 */
-
-static int init_done;
-
-static int omap_dsp_init(void)
-{
- mutex_init(&cpustat.lock);
-
- dspmem_size = 0;
-#ifdef CONFIG_ARCH_OMAP15XX
- if (cpu_is_omap15xx()) {
- 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
-#ifdef CONFIG_ARCH_OMAP24XX
- if (cpu_is_omap24xx()) {
- dspmem_base = DSP_MEM_24XX_VIRT;
- dspmem_size = DSP_MEM_24XX_SIZE;
- daram_base = OMAP24XX_DARAM_BASE;
- daram_size = OMAP24XX_DARAM_SIZE;
- saram_base = OMAP24XX_SARAM_BASE;
- saram_size = OMAP24XX_SARAM_SIZE;
- }
-#endif
-#ifdef CONFIG_ARCH_OMAP34XX
- /* To be Revisited for 3430 */
- if (cpu_is_omap34xx()) {
- return -ENODEV;
- }
-#endif
- if (dspmem_size == 0) {
- printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
- return -ENODEV;
- }
-
-#if defined(CONFIG_ARCH_OMAP1)
- dsp_ck_handle = clk_get(NULL, "dsp_ck");
- if (IS_ERR(dsp_ck_handle)) {
- printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
- return PTR_ERR(dsp_ck_handle);
- }
-
- api_ck_handle = clk_get(NULL, "api_ck");
- if (IS_ERR(api_ck_handle)) {
- printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
- if (dsp_ck_handle != NULL)
- clk_put(dsp_ck_handle);
- return PTR_ERR(api_ck_handle);
- }
-
- /* This is needed for McBSP init, released in late_initcall */
- clk_enable(api_ck_handle);
-
- __dsp_enable();
- mpui_byteswap_off();
- mpui_wordswap_on();
- tc_wordswap();
-#elif defined(CONFIG_ARCH_OMAP2)
- dsp_fck_handle = clk_get(NULL, "dsp_fck");
- if (IS_ERR(dsp_fck_handle)) {
- printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
- return PTR_ERR(dsp_fck_handle);
- }
-
- dsp_ick_handle = clk_get(NULL, "dsp_ick");
- if (IS_ERR(dsp_ick_handle)) {
- printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
- if (dsp_fck_handle != NULL)
- clk_put(dsp_fck_handle);
- return PTR_ERR(dsp_ick_handle);
- }
-#endif
-
- init_done = 1;
- pr_info("omap_dsp_init() done\n");
- return 0;
-}
-
-#if defined(CONFIG_ARCH_OMAP1)
-static int __dsp_late_init(void)
-{
- clk_disable(api_ck_handle);
- return 0;
-}
-late_initcall(__dsp_late_init);
-#endif
-
-static void dsp_cpustat_update(void)
-{
- if (!init_done)
- omap_dsp_init();
-
- if (cpustat.req == CPUSTAT_RUN) {
- if (cpustat.stat < CPUSTAT_RUN) {
-#if defined(CONFIG_ARCH_OMAP1)
- __dsp_reset();
- clk_enable(api_ck_handle);
- udelay(10);
- __dsp_run();
-#elif defined(CONFIG_ARCH_OMAP2)
- __dsp_core_disable();
- udelay(10);
- __dsp_core_enable();
-#endif
- cpustat.stat = CPUSTAT_RUN;
- }
- return;
- }
-
- /* cpustat.req < CPUSTAT_RUN */
-
- if (cpustat.stat == CPUSTAT_RUN) {
-#ifdef CONFIG_ARCH_OMAP1
- clk_disable(api_ck_handle);
-#endif
- }
-
-#ifdef CONFIG_ARCH_OMAP1
- /*
- * (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;
- }
-#endif /* CONFIG_ARCH_OMAP1 */
-
- /*
- * no user, no request
- */
- if (cpustat.stat != CPUSTAT_RESET) {
-#if defined(CONFIG_ARCH_OMAP1)
- __dsp_reset();
-#elif defined(CONFIG_ARCH_OMAP2)
- __dsp_core_disable();
-#endif
- cpustat.stat = CPUSTAT_RESET;
- }
-}
-
-void dsp_cpustat_request(enum cpustat_e req)
-{
- mutex_lock(&cpustat.lock);
- cpustat.req = req;
- dsp_cpustat_update();
- mutex_unlock(&cpustat.lock);
-}
-
-enum cpustat_e dsp_cpustat_get_stat(void)
-{
- return cpustat.stat;
-}
-
-u16 dsp_cpustat_get_icrmask(void)
-{
- return cpustat.icrmask;
-}
-
-void dsp_cpustat_set_icrmask(u16 mask)
-{
- mutex_lock(&cpustat.lock);
- cpustat.icrmask = mask;
- dsp_cpustat_update();
- mutex_unlock(&cpustat.lock);
-}
-
-#ifdef CONFIG_ARCH_OMAP1
-void omap_dsp_request_mpui(void)
-{
- mutex_lock(&cpustat.lock);
- if (cpustat.usecount.mpui++ == 0)
- dsp_cpustat_update();
- mutex_unlock(&cpustat.lock);
-}
-
-void omap_dsp_release_mpui(void)
-{
- mutex_lock(&cpustat.lock);
- 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();
- mutex_unlock(&cpustat.lock);
-}
-
-int omap_dsp_request_mem(void)
-{
- int ret = 0;
-
- mutex_lock(&cpustat.lock);
- 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:
- mutex_unlock(&cpustat.lock);
-
- return ret;
-}
-
-/*
- * release_mem will be delayed.
- */
-static void do_release_mem(struct work_struct *dummy)
-{
- mutex_lock(&cpustat.lock);
- cpustat.usecount.mem_delayed = 0;
- if (cpustat.usecount.mem == 0) {
- dsp_cpustat_update();
- if (cpustat.mem_rel_cb)
- cpustat.mem_rel_cb();
- }
- mutex_unlock(&cpustat.lock);
-}
-
-static DECLARE_DELAYED_WORK(mem_rel_work, do_release_mem);
-
-int omap_dsp_release_mem(void)
-{
- mutex_lock(&cpustat.lock);
-
- /* 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);
- }
-
- mutex_unlock(&cpustat.lock);
-
- return 0;
-}
-
-void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
-{
- mutex_lock(&cpustat.lock);
-
- 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);
-
- mutex_unlock(&cpustat.lock);
-}
-
-void dsp_unregister_mem_cb(void)
-{
- mutex_lock(&cpustat.lock);
- cpustat.mem_req_cb = NULL;
- cpustat.mem_rel_cb = NULL;
- mutex_unlock(&cpustat.lock);
-}
-#else
-void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { }
-void dsp_unregister_mem_cb(void) { }
-#endif /* CONFIG_ARCH_OMAP1 */
-
-arch_initcall(omap_dsp_init);
-
-#ifdef CONFIG_ARCH_OMAP1
-EXPORT_SYMBOL(omap_dsp_request_mpui);
-EXPORT_SYMBOL(omap_dsp_release_mpui);
-EXPORT_SYMBOL(omap_dsp_request_mem);
-EXPORT_SYMBOL(omap_dsp_release_mem);
-#endif /* CONFIG_ARCH_OMAP1 */
-
-#ifdef CONFIG_OMAP_DSP_MODULE
-#if defined(CONFIG_ARCH_OMAP1)
-EXPORT_SYMBOL(dsp_ck_handle);
-EXPORT_SYMBOL(api_ck_handle);
-#elif defined(CONFIG_ARCH_OMAP2)
-EXPORT_SYMBOL(dsp_fck_handle);
-EXPORT_SYMBOL(dsp_ick_handle);
-#endif
-EXPORT_SYMBOL(omap_dsp);
-EXPORT_SYMBOL(dspmem_base);
-EXPORT_SYMBOL(dspmem_size);
-EXPORT_SYMBOL(daram_base);
-EXPORT_SYMBOL(daram_size);
-EXPORT_SYMBOL(saram_base);
-EXPORT_SYMBOL(saram_size);
-EXPORT_SYMBOL(dsp_set_rstvect);
-EXPORT_SYMBOL(dsp_get_rstvect);
-#ifdef CONFIG_ARCH_OMAP1
-EXPORT_SYMBOL(dsp_set_idle_boot_base);
-EXPORT_SYMBOL(dsp_reset_idle_boot_base);
-#endif /* CONFIG_ARCH_OMAP1 */
-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);
-EXPORT_SYMBOL(cpu_architecture);
-EXPORT_SYMBOL(pmd_clear_bad);
-#endif
diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c
deleted file mode 100644
index 05274be..0000000
--- a/arch/arm/plat-omap/dsp/dsp_core.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <asm/delay.h>
-#include <asm/arch/mailbox.h>
-#include <asm/arch/dsp.h>
-#include <asm/arch/dsp_common.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-#include "ipbuf.h"
-
-MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
-MODULE_DESCRIPTION("OMAP DSP driver module");
-MODULE_LICENSE("GPL");
-
-static struct sync_seq *mbseq;
-static u16 mbseq_expect_tmp;
-static u16 *mbseq_expect = &mbseq_expect_tmp;
-
-extern int dsp_mem_late_init(void);
-
-/*
- * mailbox commands
- */
-extern void mbox_wdsnd(struct mbcmd *mb);
-extern void mbox_wdreq(struct mbcmd *mb);
-extern void mbox_bksnd(struct mbcmd *mb);
-extern void mbox_bkreq(struct mbcmd *mb);
-extern void mbox_bkyld(struct mbcmd *mb);
-extern void mbox_bksndp(struct mbcmd *mb);
-extern void mbox_bkreqp(struct mbcmd *mb);
-extern void mbox_tctl(struct mbcmd *mb);
-extern void mbox_poll(struct mbcmd *mb);
-#ifdef OLD_BINARY_SUPPORT
-/* v3.3 obsolete */
-extern void mbox_wdt(struct mbcmd *mb);
-#endif
-extern void mbox_suspend(struct mbcmd *mb);
-static void mbox_kfunc(struct mbcmd *mb);
-extern void mbox_tcfg(struct mbcmd *mb);
-extern void mbox_tadd(struct mbcmd *mb);
-extern void mbox_tdel(struct mbcmd *mb);
-extern void mbox_dspcfg(struct mbcmd *mb);
-extern void mbox_regrw(struct mbcmd *mb);
-extern void mbox_getvar(struct mbcmd *mb);
-extern void mbox_err(struct mbcmd *mb);
-extern void mbox_dbg(struct mbcmd *mb);
-
-static const struct cmdinfo
- cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbox_wdsnd },
- cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbox_wdreq },
- cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbox_bksnd },
- cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbox_bkreq },
- cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbox_bkyld },
- cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbox_bksndp },
- cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbox_bkreqp },
- cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbox_tctl },
- cif_poll = { "POLL", CMD_L_TYPE_NULL, mbox_poll },
-#ifdef OLD_BINARY_SUPPORT
- /* v3.3 obsolete */
- cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbox_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, mbox_suspend },
- cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbox_kfunc },
- cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbox_tcfg },
- cif_tadd = { "TADD", CMD_L_TYPE_TID, mbox_tadd },
- cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbox_tdel },
- cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL },
- cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbox_dspcfg },
- cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbox_regrw },
- cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbox_getvar },
- cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL },
- cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbox_err },
- cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbox_dbg };
-
-#define MBOX_CMD_MAX 0x80
-const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
- [MBOX_CMD_DSP_WDSND] = &cif_wdsnd,
- [MBOX_CMD_DSP_WDREQ] = &cif_wdreq,
- [MBOX_CMD_DSP_BKSND] = &cif_bksnd,
- [MBOX_CMD_DSP_BKREQ] = &cif_bkreq,
- [MBOX_CMD_DSP_BKYLD] = &cif_bkyld,
- [MBOX_CMD_DSP_BKSNDP] = &cif_bksndp,
- [MBOX_CMD_DSP_BKREQP] = &cif_bkreqp,
- [MBOX_CMD_DSP_TCTL] = &cif_tctl,
- [MBOX_CMD_DSP_POLL] = &cif_poll,
-#ifdef OLD_BINARY_SUPPORT
- [MBOX_CMD_DSP_WDT] = &cif_wdt, /* v3.3 obsolete */
-#endif
- [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
- [MBOX_CMD_DSP_PM] = &cif_pm,
- [MBOX_CMD_DSP_SUSPEND] = &cif_suspend,
- [MBOX_CMD_DSP_KFUNC] = &cif_kfunc,
- [MBOX_CMD_DSP_TCFG] = &cif_tcfg,
- [MBOX_CMD_DSP_TADD] = &cif_tadd,
- [MBOX_CMD_DSP_TDEL] = &cif_tdel,
- [MBOX_CMD_DSP_TSTOP] = &cif_tstop,
- [MBOX_CMD_DSP_DSPCFG] = &cif_dspcfg,
- [MBOX_CMD_DSP_REGRW] = &cif_regrw,
- [MBOX_CMD_DSP_GETVAR] = &cif_getvar,
- [MBOX_CMD_DSP_SETVAR] = &cif_setvar,
- [MBOX_CMD_DSP_ERR] = &cif_err,
- [MBOX_CMD_DSP_DBG] = &cif_dbg,
-};
-
-#define list_for_each_entry_safe_natural(p,n,h,m) \
- list_for_each_entry_safe(p,n,h,m)
-#define __BUILD_KFUNC(fn, dir) \
-static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
-{ \
- struct dsp_kfunc_device *p, *tmp; \
- int ret, fail = 0; \
- \
- list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) { \
- if (type && (p->type != type)) \
- continue; \
- if (p->fn == NULL) \
- continue; \
- ret = p->fn(p, stage); \
- if (ret) { \
- printk(KERN_ERR "%s %s failed\n", #fn, p->name); \
- fail++; \
- } \
- } \
- return fail; \
-}
-#define BUILD_KFUNC(fn, dir) \
-__BUILD_KFUNC(fn, dir) \
-static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp) \
-{ \
- return __dsp_kfunc_##fn##_devices(dsp, 0, 0); \
-}
-#define BUILD_KFUNC_CTL(fn, dir) \
-__BUILD_KFUNC(fn, dir) \
-static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage) \
-{ \
- return __dsp_kfunc_##fn##_devices(dsp, type, stage); \
-}
-
-BUILD_KFUNC(probe, natural)
-BUILD_KFUNC(remove, reverse)
-BUILD_KFUNC_CTL(enable, natural)
-BUILD_KFUNC_CTL(disable, reverse)
-
-int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
-{
- int try;
-
- if (*(volatile u16 *)adr == val)
- return 0;
-
- for (try = 0; try < try_cnt; try++) {
- udelay(1);
- if (*(volatile u16 *)adr == val) {
- /* success! */
- pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
- return 0;
- }
- }
-
- /* fail! */
- return -1;
-}
-
-static int mbcmd_sender_prepare(void *data)
-{
- struct mb_exarg *arg = data;
- int i, ret = 0;
- /*
- * 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, TID_FREE, 10) < 0) {
- printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
- ret = -EBUSY;
- goto out;
- }
-
- for (i = 0; i < arg->argc; i++) {
- ipbuf_sys_ad->d[i] = arg->argv[i];
- }
- ipbuf_sys_ad->s = arg->tid;
- out:
- dsp_mem_disable(ipbuf_sys_ad);
- return ret;
-}
-
-/*
- * __dsp_mbcmd_send_exarg(): mailbox dispatcher
- */
-int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
- int recovery_flag)
-{
- int ret = 0;
-
- if (unlikely(omap_dsp->enabled == 0)) {
- ret = dsp_kfunc_enable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_COMMON, 0);
- if (ret == 0)
- omap_dsp->enabled = 1;
- }
-
- /*
- * while MMU fault is set,
- * only recovery command can be executed
- */
- if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
- printk(KERN_ERR
- "mbox: mmu interrupt is set. %s is aborting.\n",
- cmd_name(*mb));
- goto out;
- }
-
- ret = omap_mbox_msg_send(omap_dsp->mbox,
- *(mbox_msg_t *)mb, (void*)arg);
- if (ret)
- goto out;
-
- if (mbseq)
- mbseq->ad_arm++;
-
- mblog_add(mb, DIR_A2D);
- out:
- return ret;
-}
-
-int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
- wait_queue_head_t *q)
-{
- int ret;
-
- DEFINE_WAIT(wait);
- prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
- ret = dsp_mbcmd_send_exarg(mb, arg);
- if (ret < 0)
- goto out;
- schedule_timeout(DSP_TIMEOUT);
- out:
- finish_wait(q, &wait);
- return ret;
-}
-
-/*
- * mbcmd receiver
- */
-static int mbcmd_receiver(void* msg)
-{
- struct mbcmd *mb = (struct mbcmd *)&msg;
-
- if (cmdinfo[mb->cmd_h] == NULL) {
- printk(KERN_ERR
- "invalid message (%08x) for mbcmd_receiver().\n",
- (mbox_msg_t)msg);
- return -1;
- }
-
- (*mbseq_expect)++;
-
- mblog_add(mb, DIR_D2A);
-
- /* call handler for the command */
- if (cmdinfo[mb->cmd_h]->handler)
- cmdinfo[mb->cmd_h]->handler(mb);
- else
- printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
- cmd_name(*mb));
- return 0;
-}
-
-static int mbsync_hold_mem_active;
-
-void dsp_mbox_start(void)
-{
- omap_mbox_init_seq(omap_dsp->mbox);
- mbseq_expect_tmp = 0;
-}
-
-void dsp_mbox_stop(void)
-{
- mbseq = NULL;
- mbseq_expect = &mbseq_expect_tmp;
-}
-
-int dsp_mbox_config(void *p)
-{
- 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;
-}
-
-static int __init dsp_mbox_init(void)
-{
- omap_dsp->mbox = omap_mbox_get("dsp");
- if (IS_ERR(omap_dsp->mbox)) {
- printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
- return -ENODEV;
- }
-
- omap_dsp->mbox->rxq->callback = mbcmd_receiver;
- omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
-
- return 0;
-}
-
-static void dsp_mbox_exit(void)
-{
- omap_dsp->mbox->txq->callback = NULL;
- omap_dsp->mbox->rxq->callback = NULL;
-
- omap_mbox_put(omap_dsp->mbox);
-
- if (mbsync_hold_mem_active) {
- dsp_mem_disable((void *)daram_base);
- mbsync_hold_mem_active = 0;
- }
-}
-
-/*
- * kernel function dispatcher
- */
-extern void mbox_fbctl_upd(void);
-extern void mbox_fbctl_disable(struct mbcmd *mb);
-
-static void mbox_kfunc_fbctl(struct mbcmd *mb)
-{
- switch (mb->data) {
- case FBCTL_UPD:
- mbox_fbctl_upd();
- break;
- case FBCTL_DISABLE:
- mbox_fbctl_disable(mb);
- break;
- default:
- printk(KERN_ERR
- "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
- }
-}
-
-/*
- * dspgw: KFUNC message handler
- */
-static void mbox_kfunc_power(unsigned short data)
-{
- int ret = -1;
-
- switch (data) {
- case DVFS_START: /* ACK from DSP */
- /* TBD */
- break;
- case AUDIO_PWR_UP:
- ret = dsp_kfunc_enable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_AUDIO, 0);
- if (ret == 0)
- ret++;
- break;
- case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
- ret = dsp_kfunc_disable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_AUDIO, 1);
- break;
- case AUDIO_PWR_DOWN2:
- ret = dsp_kfunc_disable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_AUDIO, 2);
- break;
- case DSP_PWR_DOWN:
- ret = dsp_kfunc_disable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_COMMON, 0);
- if (ret == 0)
- omap_dsp->enabled = 0;
- break;
- default:
- printk(KERN_ERR
- "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
- break;
- }
-
- if (unlikely(ret < 0)) {
- printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
- return;
- }
-
- if (likely(ret == 0))
- return;
-
- mbcompose_send(KFUNC, KFUNC_POWER, data);
-}
-
-static void mbox_kfunc(struct mbcmd *mb)
-{
- switch (mb->cmd_l) {
- case KFUNC_FBCTL:
- mbox_kfunc_fbctl(mb);
- break;
- case KFUNC_POWER:
- mbox_kfunc_power(mb->data);
- break;
- default:
- printk(KERN_ERR
- "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
- }
-}
-
-#if defined(CONFIG_ARCH_OMAP1)
-static inline void dsp_clk_enable(void) {}
-static inline void dsp_clk_disable(void) {}
-#elif defined(CONFIG_ARCH_OMAP2)
-static inline void dsp_clk_enable(void)
-{
- u32 r;
-
- /*XXX should be handled in mach-omap[1,2] XXX*/
- prm_write_mod_reg(OMAP24XX_FORCESTATE | (1 << OMAP_POWERSTATE_SHIFT),
- OMAP24XX_DSP_MOD, PM_PWSTCTRL);
-
- r = cm_read_mod_reg(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
- r |= OMAP2420_AUTO_DSP_IPI;
- cm_write_mod_reg(r, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
-
- r = cm_read_mod_reg(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
- r |= OMAP24XX_AUTOSTATE_DSP;
- cm_write_mod_reg(r, OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
-
- clk_enable(dsp_fck_handle);
- clk_enable(dsp_ick_handle);
- __dsp_per_enable();
-}
-static inline void dsp_clk_disable(void)
-{
- __dsp_per_disable();
- clk_disable(dsp_ick_handle);
- clk_disable(dsp_fck_handle);
-
- prm_write_mod_reg(OMAP24XX_FORCESTATE | (3 << OMAP_POWERSTATE_SHIFT),
- OMAP24XX_DSP_MOD, PM_PWSTCTRL);
-}
-#endif
-
-int dsp_late_init(void)
-{
- int ret;
-
- dsp_clk_enable();
- ret = dsp_mem_late_init();
- if (ret)
- return ret;
- ret = dsp_mbox_init();
- if (ret)
- goto fail_mbox;
-#ifdef CONFIG_ARCH_OMAP1
- dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
-#endif
- ret = dsp_kfunc_enable_devices(omap_dsp,
- DSP_KFUNC_DEV_TYPE_COMMON, 0);
- if (ret)
- goto fail_kfunc;
- omap_dsp->enabled = 1;
-
- return 0;
-
- fail_kfunc:
- dsp_mbox_exit();
- fail_mbox:
- dsp_clk_disable();
-
- return ret;
-}
-
-extern int dsp_ctl_core_init(void);
-extern void dsp_ctl_core_exit(void);
-extern int dsp_ctl_init(void);
-extern void dsp_ctl_exit(void);
-extern int dsp_mem_init(void);
-extern void dsp_mem_exit(void);
-extern void mblog_init(void);
-extern void mblog_exit(void);
-extern int dsp_taskmod_init(void);
-extern void dsp_taskmod_exit(void);
-
-/*
- * driver functions
- */
-static int __init dsp_drv_probe(struct platform_device *pdev)
-{
- int ret;
- struct omap_dsp *info;
- struct dsp_platform_data *pdata = pdev->dev.platform_data;
-
- dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
-
- info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
- if (unlikely(info == NULL)) {
- dev_dbg(&pdev->dev, "no memory for info\n");
- return -ENOMEM;
- }
- platform_set_drvdata(pdev, info);
- omap_dsp = info;
-
- mutex_init(&info->lock);
- info->dev = &pdev->dev;
- info->kdev_list = &pdata->kdev_list;
-
- ret = dsp_kfunc_probe_devices(info);
- if (ret) {
- ret = -ENXIO;
- goto fail_kfunc;
- }
-
- ret = dsp_ctl_core_init();
- if (ret)
- goto fail_ctl_core;
- ret = dsp_mem_init();
- if (ret)
- goto fail_mem;
- ret = dsp_ctl_init();
- if (unlikely(ret))
- goto fail_ctl_init;
- mblog_init();
- ret = dsp_taskmod_init();
- if (ret)
- goto fail_taskmod;
-
- return 0;
-
- fail_taskmod:
- mblog_exit();
- dsp_ctl_exit();
- fail_ctl_init:
- dsp_mem_exit();
- fail_mem:
- dsp_ctl_core_exit();
- fail_ctl_core:
- dsp_kfunc_remove_devices(info);
- fail_kfunc:
- kfree(info);
-
- return ret;
-}
-
-static int dsp_drv_remove(struct platform_device *pdev)
-{
- struct omap_dsp *info = platform_get_drvdata(pdev);
-
- dsp_cpustat_request(CPUSTAT_RESET);
-
- dsp_cfgstat_request(CFGSTAT_CLEAN);
- dsp_mbox_exit();
- dsp_taskmod_exit();
- mblog_exit();
- dsp_ctl_exit();
- dsp_mem_exit();
-
- dsp_ctl_core_exit();
-
-#ifdef CONFIG_ARCH_OMAP2
- __dsp_per_disable();
- clk_disable(dsp_ick_handle);
- clk_disable(dsp_fck_handle);
-#endif
- dsp_kfunc_remove_devices(info);
- kfree(info);
-
- return 0;
-}
-
-#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
-static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
-{
- dsp_cfgstat_request(CFGSTAT_SUSPEND);
-
- return 0;
-}
-
-static int dsp_drv_resume(struct platform_device *pdev)
-{
- dsp_cfgstat_request(CFGSTAT_RESUME);
-
- return 0;
-}
-#else
-#define dsp_drv_suspend NULL
-#define dsp_drv_resume NULL
-#endif /* CONFIG_PM */
-
-static struct platform_driver dsp_driver = {
- .probe = dsp_drv_probe,
- .remove = dsp_drv_remove,
- .suspend = dsp_drv_suspend,
- .resume = dsp_drv_resume,
- .driver = {
- .name = "dsp",
- },
-};
-
-static int __init omap_dsp_mod_init(void)
-{
- return platform_driver_register(&dsp_driver);
-}
-
-static void __exit omap_dsp_mod_exit(void)
-{
- platform_driver_unregister(&dsp_driver);
-}
-
-/* module dependency: need mailbox module that have mbox_dsp_info */
-extern struct omap_mbox mbox_dsp_info;
-struct omap_mbox *mbox_dep = &mbox_dsp_info;
-
-module_init(omap_dsp_mod_init);
-module_exit(omap_dsp_mod_exit);
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c
deleted file mode 100644
index 79c1fdf..0000000
--- a/arch/arm/plat-omap/dsp/dsp_ctl.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/ioctls.h>
-#include <asm/arch/mailbox.h>
-#include <asm/arch/dsp.h>
-#include "hardware_dsp.h"
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-#include "ipbuf.h"
-
-enum dsp_space_e {
- SPACE_MEM,
- SPACE_IO,
-};
-
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
-static enum fbstat_e {
- FBSTAT_DISABLED = 0,
- FBSTAT_ENABLED,
- FBSTAT_MAX,
-} fbstat = FBSTAT_ENABLED;
-#endif
-
-static enum cfgstat_e cfgstat;
-int mbox_revision;
-static u8 n_stask;
-
-static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
-static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-
-#define __ATTR_RW(_name, _mode) { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
- .show = _name##_show, \
- .store = _name##_store, \
-}
-
-static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
-static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
-static struct device_attribute dev_attr_icrmask = __ATTR_RW(icrmask, 0644);
-static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
-
-/*
- * misc interactive mailbox command operations
- */
-static struct misc_mb_wait_struct {
- struct mutex lock;
- wait_queue_head_t wait_q;
- u8 cmd_h;
- u8 cmd_l;
- u16 *retvp;
-} misc_mb_wait = {
- .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
- .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
-};
-
-static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
- u16 *retvp)
-{
- struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
- int ret = 0;
-
- if (mutex_lock_interruptible(&misc_mb_wait.lock))
- return -EINTR;
-
- misc_mb_wait.cmd_h = mb.cmd_h;
- misc_mb_wait.cmd_l = mb.cmd_l;
- misc_mb_wait.retvp = retvp;
- dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
-
- if (misc_mb_wait.cmd_h != 0)
- ret = -EINVAL;
-
- mutex_unlock(&misc_mb_wait.lock);
- return ret;
-}
-
-#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
- __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
- (data), (retvp));
-
-static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
-{
- volatile u16 *buf;
- int i;
-
- /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
- if (!waitqueue_active(&misc_mb_wait.wait_q) ||
- (misc_mb_wait.cmd_h != mb->cmd_h) ||
- (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
- const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
- char cmdstr[32];
-
- if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
- sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
- else
- strcpy(cmdstr, ci->name);
- printk(KERN_WARNING
- "mbox: unexpected command %s received!\n", cmdstr);
- return -1;
- }
-
- /*
- * if argc == 1, receive data through mbox:data register.
- * if argc > 1, receive through ipbuf_sys.
- */
- if (argc == 1)
- misc_mb_wait.retvp[0] = mb->data;
- else if (argc > 1) {
- if (dsp_mem_enable(ipbuf_sys_da) < 0) {
- printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
- cmdinfo[mb->cmd_h]->name);
- return -1;
- }
- if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
- printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
- cmdinfo[mb->cmd_h]->name);
- dsp_mem_disable(ipbuf_sys_da);
- return -1;
- }
- /* need word access. do not use memcpy. */
- buf = ipbuf_sys_da->d;
- for (i = 0; i < argc; i++)
- misc_mb_wait.retvp[i] = buf[i];
- release_ipbuf_pvt(ipbuf_sys_da);
- dsp_mem_disable(ipbuf_sys_da);
- }
-
- misc_mb_wait.cmd_h = 0;
- wake_up_interruptible(&misc_mb_wait.wait_q);
- return 0;
-}
-
-static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
-{
- u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
- int ret;
-
- ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
- if ((ret < 0) && (ret != -EINTR))
- printk(KERN_ERR "omapdsp: register read error!\n");
-
- return ret;
-}
-
-static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
-{
- u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
- struct mb_exarg arg = {
- .tid = TID_ANON,
- .argc = 1,
- .argv = &val,
- };
-
- mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
- return 0;
-}
-
-static int dsp_getvar(u8 varid, u16 *val)
-{
- int ret;
-
- ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
- if ((ret < 0) && (ret != -EINTR))
- printk(KERN_ERR "omapdsp: variable read error!\n");
-
- return ret;
-}
-
-static int dsp_setvar(u8 varid, u16 val)
-{
- mbcompose_send(SETVAR, varid, val);
- return 0;
-}
-
-/*
- * dsp_cfg() return value
- * = 0: OK
- * = 1: failed, but state is clear. (DSPCFG command failed)
- * < 0: failed. need cleanup.
- */
-static int dsp_cfg(void)
-{
- int ret = 0;
-
-#ifdef CONFIG_ARCH_OMAP1
- /* for safety */
- dsp_mem_usecount_clear();
-#endif
-
- /*
- * DSPCFG command and dsp_mem_start() must be called
- * while internal mem is on.
- */
- dsp_mem_enable((void *)dspmem_base);
-
- dsp_mbox_start();
- dsp_twch_start();
- dsp_mem_start();
- dsp_err_start();
-
- mbox_revision = -1;
-
- ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
- if (ret < 0) {
- if (ret != -EINTR)
- printk(KERN_ERR "omapdsp: configuration error!\n");
- ret = 1;
- goto out;
- }
-
-#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
- /*
- * MBREV 3.2 or earlier doesn't assume DMA domain is on
- * when DSPCFG command is sent
- */
- if ((mbox_revision == MBREV_3_0) ||
- (mbox_revision == MBREV_3_2)) {
- if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
- goto out;
- }
-#endif
-
- if ((ret = dsp_task_config_all(n_stask)) < 0)
- goto out;
-
- /* initialization */
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
- fbstat = FBSTAT_ENABLED;
-#endif
-
- /* send parameter */
- ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
- if (ret < 0)
- goto out;
-
- /* create runtime sysfs entries */
- ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
- if (ret)
- printk(KERN_ERR "device_create_file failed: %d\n", ret);
- out:
- dsp_mem_disable((void *)dspmem_base);
- return ret;
-}
-
-static int dsp_uncfg(void)
-{
- if (dsp_taskmod_busy()) {
- printk(KERN_WARNING "omapdsp: tasks are busy.\n");
- return -EBUSY;
- }
-
- /* FIXME: lock task module */
-
- /* remove runtime sysfs entries */
- device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
-
- dsp_mbox_stop();
- dsp_twch_stop();
- dsp_mem_stop();
- dsp_err_stop();
- dsp_dbg_stop();
- dsp_task_unconfig_all();
- ipbuf_stop();
-
- return 0;
-}
-
-static int dsp_suspend(void)
-{
- int ret;
-
- ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
- if (ret < 0) {
- if (ret != -EINVAL)
- printk(KERN_ERR "omapdsp: DSP suspend error!\n");
- return ret;
- }
-
- udelay(100); /* wait for DSP-side execution */
- return 0;
-}
-
-int dsp_cfgstat_request(enum cfgstat_e st_req)
-{
- static DEFINE_MUTEX(cfgstat_lock);
- int ret = 0, ret_override = 0;
-
- if (mutex_lock_interruptible(&cfgstat_lock))
- return -EINTR;
-
-again:
- switch (st_req) {
-
- /* cfgstat takes CLEAN, READY or SUSPEND,
- while st_req can take SUSPEND in addition. */
-
- case CFGSTAT_CLEAN:
- if (cfgstat == CFGSTAT_CLEAN)
- goto up_out;
- if ((ret = dsp_uncfg()) < 0)
- goto up_out;
- break;
-
- case CFGSTAT_READY:
- if (cfgstat != CFGSTAT_CLEAN) {
- printk(KERN_ERR "omapdsp: DSP is ready already!\n");
- ret = -EINVAL;
- goto up_out;
- }
-
- ret = dsp_cfg();
- if (ret > 0) { /* failed, but state is clear. */
- ret = -EINVAL;
- goto up_out;
- } else if (ret < 0) { /* failed, need cleanup. */
- st_req = CFGSTAT_CLEAN;
- ret_override = ret;
- goto again;
- }
- break;
-
- /*
- * suspend / resume
- * DSP is not reset within this code, but done in omap_pm_suspend.
- * so if these functions are called from sysfs,
- * DSP should be reset / unreset out of these functions.
- */
- case CFGSTAT_SUSPEND:
- switch (cfgstat) {
-
- case CFGSTAT_CLEAN:
- if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
- printk(KERN_WARNING
- "omapdsp: illegal operation -- trying "
- "suspend DSP while it is running but "
- "not configured.\n"
- " Resetting DSP.\n");
- dsp_cpustat_request(CPUSTAT_RESET);
- ret = -EINVAL;
- }
- goto up_out;
-
- case CFGSTAT_READY:
- if ((ret = dsp_suspend()) < 0)
- goto up_out;
- break;
-
- case CFGSTAT_SUSPEND:
- goto up_out;
-
- default:
- BUG();
-
- }
-
- break;
-
- case CFGSTAT_RESUME:
- if (cfgstat != CFGSTAT_SUSPEND) {
- printk(KERN_WARNING
- "omapdsp: DSP resume request, but DSP is not in "
- "suspend state.\n");
- ret = -EINVAL;
- goto up_out;
- }
- st_req = CFGSTAT_READY;
- break;
-
- default:
- BUG();
-
- }
-
- cfgstat = st_req;
-up_out:
- mutex_unlock(&cfgstat_lock);
- return ret_override ? ret_override : ret;
-}
-
-enum cfgstat_e dsp_cfgstat_get_stat(void)
-{
- return cfgstat;
-}
-
-/*
- * polls all tasks
- */
-static int dsp_poll(void)
-{
- int ret;
-
- ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
- if ((ret < 0) && (ret != -EINTR))
- printk(KERN_ERR "omapdsp: poll error!\n");
-
- return ret;
-}
-
-int dsp_set_runlevel(u8 level)
-{
- if (level == RUNLEVEL_RECOVERY) {
- if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
- return -EINVAL;
- } else {
- if ((level < RUNLEVEL_USER) ||
- (level > RUNLEVEL_SUPER))
- return -EINVAL;
- if (mbcompose_send(RUNLEVEL, level, 0) < 0)
- return -EINVAL;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
-static void dsp_fbctl_enable(void)
-{
- mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
-}
-
-static int dsp_fbctl_disable(void)
-{
- int ret;
-
- ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
- NULL);
- if ((ret < 0) && (ret != -EINTR))
- printk(KERN_ERR "omapdsp: fb disable error!\n");
-
- return 0;
-}
-
-static int dsp_fbstat_request(enum fbstat_e st)
-{
- static DEFINE_MUTEX(fbstat_lock);
- int ret = 0;
-
- if (mutex_lock_interruptible(&fbstat_lock))
- return -EINTR;
-
- if (st == fbstat)
- goto up_out;
-
- switch (st) {
- case FBSTAT_ENABLED:
- dsp_fbctl_enable();
- break;
- case FBSTAT_DISABLED:
- if ((ret = dsp_fbctl_disable()) < 0)
- goto up_out;
- break;
- default:
- BUG();
- }
-
- fbstat = st;
-up_out:
- mutex_unlock(&fbstat_lock);
- return 0;
-}
-#endif /* CONFIG_OMAP_DSP_FBEXPORT */
-
-/*
- * DSP control device file operations
- */
-static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
-
- switch (cmd) {
- /*
- * command level 1: commands which don't need lock
- */
- case DSPCTL_IOCTL_RUN:
- dsp_cpustat_request(CPUSTAT_RUN);
- break;
-
- case DSPCTL_IOCTL_RESET:
- dsp_cpustat_request(CPUSTAT_RESET);
- break;
-
- case DSPCTL_IOCTL_SETRSTVECT:
- ret = dsp_set_rstvect((dsp_long_t)arg);
- break;
-
-#ifdef CONFIG_ARCH_OMAP1
- case DSPCTL_IOCTL_CPU_IDLE:
- dsp_cpustat_request(CPUSTAT_CPU_IDLE);
- break;
-
- case DSPCTL_IOCTL_GBL_IDLE:
- dsp_cpustat_request(CPUSTAT_GBL_IDLE);
- break;
-
- case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
- mpui_wordswap_on();
- break;
-
- case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
- mpui_wordswap_off();
- break;
-
- case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
- mpui_byteswap_on();
- break;
-
- case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
- mpui_byteswap_off();
- break;
-#endif /* CONFIG_ARCH_OMAP1 */
-
- case DSPCTL_IOCTL_TASKCNT:
- ret = dsp_task_count();
- break;
-
- case DSPCTL_IOCTL_MBSEND:
- {
- struct omap_dsp_mailbox_cmd u_cmd;
- mbox_msg_t msg;
- if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
- return -EFAULT;
- msg = (u_cmd.cmd << 16) | u_cmd.data;
- ret = dsp_mbcmd_send((struct mbcmd *)&msg);
- break;
- }
-
- case DSPCTL_IOCTL_SETVAR:
- {
- struct omap_dsp_varinfo var;
- if (copy_from_user(&var, (void *)arg, sizeof(var)))
- return -EFAULT;
- ret = dsp_setvar(var.varid, var.val[0]);
- break;
- }
-
- case DSPCTL_IOCTL_RUNLEVEL:
- ret = dsp_set_runlevel(arg);
- break;
-
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
- case DSPCTL_IOCTL_FBEN:
- ret = dsp_fbstat_request(FBSTAT_ENABLED);
- break;
-#endif
-
- /*
- * command level 2: commands which need lock
- */
- case DSPCTL_IOCTL_DSPCFG:
- ret = dsp_cfgstat_request(CFGSTAT_READY);
- break;
-
- case DSPCTL_IOCTL_DSPUNCFG:
- ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
- break;
-
- case DSPCTL_IOCTL_POLL:
- ret = dsp_poll();
- break;
-
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
- case DSPCTL_IOCTL_FBDIS:
- ret = dsp_fbstat_request(FBSTAT_DISABLED);
- break;
-#endif
-
- case DSPCTL_IOCTL_SUSPEND:
- if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
- break;
- dsp_cpustat_request(CPUSTAT_RESET);
- break;
-
- case DSPCTL_IOCTL_RESUME:
- if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
- break;
- dsp_cpustat_request(CPUSTAT_RUN);
- break;
-
- case DSPCTL_IOCTL_REGMEMR:
- {
- struct omap_dsp_reginfo *u_reg = (void *)arg;
- u16 adr, val;
-
- if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
- return -EFAULT;
- if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
- return ret;
- if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
- return -EFAULT;
- break;
- }
-
- case DSPCTL_IOCTL_REGMEMW:
- {
- struct omap_dsp_reginfo reg;
-
- if (copy_from_user(®, (void *)arg, sizeof(reg)))
- return -EFAULT;
- ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
- break;
- }
-
- case DSPCTL_IOCTL_REGIOR:
- {
- struct omap_dsp_reginfo *u_reg = (void *)arg;
- u16 adr, val;
-
- if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
- return -EFAULT;
- if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
- return ret;
- if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
- return -EFAULT;
- break;
- }
-
- case DSPCTL_IOCTL_REGIOW:
- {
- struct omap_dsp_reginfo reg;
-
- if (copy_from_user(®, (void *)arg, sizeof(reg)))
- return -EFAULT;
- ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
- break;
- }
-
- case DSPCTL_IOCTL_GETVAR:
- {
- struct omap_dsp_varinfo *u_var = (void *)arg;
- u8 varid;
- u16 val[5]; /* maximum */
- int argc;
-
- if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
- return -EFAULT;
- switch (varid) {
- case VARID_ICRMASK:
- argc = 1;
- break;
- case VARID_LOADINFO:
- argc = 5;
- break;
- default:
- return -EINVAL;
- }
- if ((ret = dsp_getvar(varid, val)) < 0)
- return ret;
- if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
- return -EFAULT;
- break;
- }
-
- default:
- return -ENOIOCTLCMD;
- }
-
- return ret;
-}
-
-/*
- * functions called from mailbox interrupt routine
- */
-void mbox_suspend(struct mbcmd *mb)
-{
- misc_mbcmd_response(mb, 0, 0);
-}
-
-void mbox_dspcfg(struct mbcmd *mb)
-{
- u8 last = mb->cmd_l & 0x80;
- u8 cfgcmd = mb->cmd_l & 0x7f;
- static dsp_long_t tmp_ipb_adr;
-
- if (!waitqueue_active(&misc_mb_wait.wait_q) ||
- (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
- printk(KERN_WARNING
- "mbox: DSPCFG command received, "
- "but nobody is waiting for it...\n");
- return;
- }
-
- /* mailbox protocol check */
- if (cfgcmd == DSPCFG_PROTREV) {
- mbox_revision = mb->data;
- if (mbox_revision == MBPROT_REVISION)
- return;
-#ifdef OLD_BINARY_SUPPORT
- else if ((mbox_revision == MBREV_3_0) ||
- (mbox_revision == MBREV_3_2)) {
- printk(KERN_WARNING
- "mbox: ***** old DSP binary *****\n"
- " Please update your DSP application.\n");
- return;
- }
-#endif
- else {
- printk(KERN_ERR
- "mbox: protocol revision check error!\n"
- " expected=0x%04x, received=0x%04x\n",
- MBPROT_REVISION, mb->data);
- mbox_revision = -1;
- goto abort1;
- }
- }
-
- /*
- * following commands are accepted only after
- * revision check has been passed.
- */
- if (!mbox_revision < 0) {
- pr_info("mbox: DSPCFG command received, "
- "but revision check has not been passed.\n");
- return;
- }
-
- switch (cfgcmd) {
- case DSPCFG_SYSADRH:
- tmp_ipb_adr = (u32)mb->data << 16;
- break;
-
- case DSPCFG_SYSADRL:
- tmp_ipb_adr |= mb->data;
- break;
-
- case DSPCFG_ABORT:
- goto abort1;
-
- default:
- printk(KERN_ERR
- "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
- mb->cmd_l, mb->data);
- return;
- }
-
- if (last) {
- void *badr;
- u16 bln;
- u16 bsz;
- volatile u16 *buf;
- void *ipb_sys_da, *ipb_sys_ad;
- void *mbseq; /* FIXME: 3.4 obsolete */
- short *dbg_buf;
- u16 dbg_buf_sz, dbg_line_sz;
- struct mem_sync_struct mem_sync, *mem_syncp;
-
- ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
- if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
- goto abort1;
-
- if (dsp_mem_enable(ipbuf_sys_da) < 0) {
- printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
- goto abort1;
- }
- if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
- printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
- dsp_mem_disable(ipbuf_sys_da);
- goto abort1;
- }
- /*
- * read configuration data on system IPBUF
- * we must read with 16bit-access
- */
-#ifdef OLD_BINARY_SUPPORT
- if (mbox_revision == MBPROT_REVISION) {
-#endif
- 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 = 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 (mbox_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 (mbox_revision == MBREV_3_0) {
- buf = ipbuf_sys_da->d;
- 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 */
- dsp_mem_disable(ipbuf_sys_da);
- goto abort1;
- }
-#endif /* OLD_BINARY_SUPPORT */
-
- release_ipbuf_pvt(ipbuf_sys_da);
- dsp_mem_disable(ipbuf_sys_da);
-
- /*
- * 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_mbox_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;
-
- misc_mb_wait.cmd_h = 0;
- wake_up_interruptible(&misc_mb_wait.wait_q);
- }
- return;
-
-abort2:
- ipbuf_stop();
-abort1:
- wake_up_interruptible(&misc_mb_wait.wait_q);
- return;
-}
-
-void mbox_poll(struct mbcmd *mb)
-{
- misc_mbcmd_response(mb, 0, 0);
-}
-
-void mbox_regrw(struct mbcmd *mb)
-{
- switch (mb->cmd_l) {
- case REGRW_DATA:
- misc_mbcmd_response(mb, 1, 0);
- break;
- default:
- printk(KERN_ERR
- "mbox: Illegal REGRW command: "
- "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
- return;
- }
-}
-
-void mbox_getvar(struct mbcmd *mb)
-{
- switch (mb->cmd_l) {
- case VARID_ICRMASK:
- misc_mbcmd_response(mb, 1, 1);
- break;
- case VARID_LOADINFO:
- misc_mbcmd_response(mb, 5, 1);
- break;
- default:
- printk(KERN_ERR
- "mbox: Illegal GETVAR command: "
- "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
- return;
- }
-}
-
-void mbox_fbctl_disable(struct mbcmd *mb)
-{
- misc_mbcmd_response(mb, 0, 0);
-}
-
-struct file_operations dsp_ctl_fops = {
- .owner = THIS_MODULE,
- .ioctl = dsp_ctl_ioctl,
-};
-
-/*
- * sysfs files
- */
-
-/* ifver */
-static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int len = 0;
-
- /*
- * I/F VERSION descriptions:
- *
- * 3.2: sysfs / udev support
- * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
- * 3.3: added following ioctls
- * DSPCTL_IOCTL_GBL_IDLE
- * DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
- * DSPCTL_IOCTL_POLL
- */
-
- /*
- * print all supporting I/F VERSIONs, like followings.
- *
- * 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;
-}
-
-/* cpustat */
-static char *cpustat_name[CPUSTAT_MAX] = {
- [CPUSTAT_RESET] = "reset",
-#ifdef CONFIG_ARCH_OMAP1
- [CPUSTAT_GBL_IDLE] = "gbl_idle",
- [CPUSTAT_CPU_IDLE] = "cpu_idle",
-#endif
- [CPUSTAT_RUN] = "run",
-};
-
-static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
-}
-
-/* icrmask */
-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)
-{
- u16 mask;
- int ret;
-
- mask = simple_strtol(buf, NULL, 16);
- dsp_cpustat_set_icrmask(mask);
-
- if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
- ret = dsp_setvar(VARID_ICRMASK, mask);
- if (ret < 0)
- return ret;
- }
-
- return count;
-}
-
-/* loadinfo */
-static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int len;
- int ret;
- u16 val[5];
-
- if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
- return ret;
-
- /*
- * load info value range is 0(free) - 10000(busy):
- * if CPU load is not measured on DSP, it sets 0xffff at val[0].
- */
-
- if (val[0] == 0xffff) {
- len = sprintf(buf,
- "currently DSP load info is not available.\n");
- goto out;
- }
-
- len = sprintf(buf,
- "DSP load info:\n"
- " 10ms average = %3d.%02d%%\n"
- " 1sec average = %3d.%02d%% busiest 10ms = %3d.%02d%%\n"
- " 1min average = %3d.%02d%% busiest 1s = %3d.%02d%%\n",
- val[0]/100, val[0]%100,
- val[1]/100, val[1]%100, val[2]/100, val[2]%100,
- val[3]/100, val[3]%100, val[4]/100, val[4]%100);
-out:
- return len;
-}
-
-int __init dsp_ctl_init(void)
-{
- int ret;
-
- ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
- if (unlikely(ret))
- return ret;
- ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
- if (unlikely(ret))
- goto fail_create_cpustat;
- ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
- if (unlikely(ret))
- goto fail_create_icrmask;
-
- return 0;
-
-fail_create_icrmask:
- device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
-fail_create_cpustat:
- device_remove_file(omap_dsp->dev, &dev_attr_ifver);
-
- return ret;
-}
-
-void dsp_ctl_exit(void)
-{
- device_remove_file(omap_dsp->dev, &dev_attr_ifver);
- device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
- device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
-}
diff --git a/arch/arm/plat-omap/dsp/dsp_ctl_core.c b/arch/arm/plat-omap/dsp/dsp_ctl_core.c
deleted file mode 100644
index 956ef26..0000000
--- a/arch/arm/plat-omap/dsp/dsp_ctl_core.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include "dsp.h"
-
-#define CTL_MINOR 0
-#define MEM_MINOR 1
-#define TWCH_MINOR 2
-#define ERR_MINOR 3
-
-static struct class *dsp_ctl_class;
-extern struct file_operations dsp_ctl_fops,
- dsp_mem_fops,
- dsp_twch_fops,
- dsp_err_fops;
-
-static int dsp_ctl_core_open(struct inode *inode, struct file *file)
-{
- static DEFINE_MUTEX(open_lock);
- int ret = 0;
-
- if (mutex_lock_interruptible(&open_lock))
- return -EINTR;
- if (omap_dsp->initialized == 0) {
- ret = dsp_late_init();
- if (ret != 0) {
- mutex_unlock(&open_lock);
- return ret;
- }
- omap_dsp->initialized = 1;
- }
- mutex_unlock(&open_lock);
-
- switch (iminor(inode)) {
- case CTL_MINOR:
- file->f_op = &dsp_ctl_fops;
- break;
- case MEM_MINOR:
- file->f_op = &dsp_mem_fops;
- break;
- case TWCH_MINOR:
- file->f_op = &dsp_twch_fops;
- break;
- case ERR_MINOR:
- file->f_op = &dsp_err_fops;
- break;
- default:
- return -ENXIO;
- }
- if (file->f_op && file->f_op->open)
- return file->f_op->open(inode, file);
- return 0;
-}
-
-static struct file_operations dsp_ctl_core_fops = {
- .owner = THIS_MODULE,
- .open = dsp_ctl_core_open,
-};
-
-static const struct dev_list {
- unsigned int minor;
- char *devname;
- umode_t mode;
-} dev_list[] = {
- {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)
-{
- int retval;
- int i;
-
- retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
- &dsp_ctl_core_fops);
- if (retval < 0) {
- printk(KERN_ERR
- "omapdsp: failed to register dspctl device: %d\n",
- retval);
- return retval;
- }
-
- dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
- for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_create(dsp_ctl_class, NULL,
- MKDEV(OMAP_DSP_CTL_MAJOR,
- dev_list[i].minor),
- dev_list[i].devname);
- }
-
- return 0;
-}
-
-void dsp_ctl_core_exit(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_destroy(dsp_ctl_class,
- MKDEV(OMAP_DSP_CTL_MAJOR,
- dev_list[i].minor));
- }
- class_destroy(dsp_ctl_class);
-
- unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
-}
diff --git a/arch/arm/plat-omap/dsp/dsp_mbcmd.h b/arch/arm/plat-omap/dsp/dsp_mbcmd.h
deleted file mode 100644
index fb35749..0000000
--- a/arch/arm/plat-omap/dsp/dsp_mbcmd.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __PLAT_OMAP_DSP_MBCMD_H
-#define __PLAT_OMAP_DSP_MBCMD_H
-/*
- * mailbox command: 0x00 - 0x7f
- * when a driver wants to use mailbox, it must reserve mailbox commands here.
- */
-#define MBOX_CMD_DSP_WDSND 0x10
-#define MBOX_CMD_DSP_WDREQ 0x11
-#define MBOX_CMD_DSP_BKSND 0x20
-#define MBOX_CMD_DSP_BKREQ 0x21
-#define MBOX_CMD_DSP_BKYLD 0x23
-#define MBOX_CMD_DSP_BKSNDP 0x24
-#define MBOX_CMD_DSP_BKREQP 0x25
-#define MBOX_CMD_DSP_TCTL 0x30
-#define MBOX_CMD_DSP_TCTLDATA 0x31
-#define MBOX_CMD_DSP_POLL 0x32
-#define MBOX_CMD_DSP_WDT 0x50
-#define MBOX_CMD_DSP_RUNLEVEL 0x51
-#define MBOX_CMD_DSP_PM 0x52
-#define MBOX_CMD_DSP_SUSPEND 0x53
-#define MBOX_CMD_DSP_KFUNC 0x54
-#define MBOX_CMD_DSP_TCFG 0x60
-#define MBOX_CMD_DSP_TADD 0x62
-#define MBOX_CMD_DSP_TDEL 0x63
-#define MBOX_CMD_DSP_TSTOP 0x65
-#define MBOX_CMD_DSP_DSPCFG 0x70
-#define MBOX_CMD_DSP_REGRW 0x72
-#define MBOX_CMD_DSP_GETVAR 0x74
-#define MBOX_CMD_DSP_SETVAR 0x75
-#define MBOX_CMD_DSP_ERR 0x78
-#define MBOX_CMD_DSP_DBG 0x79
-
-/*
- * DSP mailbox protocol definitions
- */
-#define MBPROT_REVISION 0x0019
-
-#define TCTL_TINIT 0x0000
-#define TCTL_TEN 0x0001
-#define TCTL_TDIS 0x0002
-#define TCTL_TCLR 0x0003
-#define TCTL_TCLR_FORCE 0x0004
-
-#define RUNLEVEL_USER 0x01
-#define RUNLEVEL_SUPER 0x0e
-#define RUNLEVEL_RECOVERY 0x10
-
-#define PM_DISABLE 0x00
-#define PM_ENABLE 0x01
-
-#define KFUNC_FBCTL 0x00
-#define KFUNC_POWER 0x01
-
-#define FBCTL_UPD 0x0000
-#define FBCTL_ENABLE 0x0002
-#define FBCTL_DISABLE 0x0003
-
-/* KFUNC_POWER */
-#define AUDIO_PWR_UP 0x0000 /* ARM(exe/ack) <-> DSP(req) */
-#define AUDIO_PWR_DOWN 0x0001 /* ARM(exe) <- DSP(req) */
-#define AUDIO_PWR_DOWN1 AUDIO_PWR_DOWN
-#define AUDIO_PWR_DOWN2 0x0002
-#define DSP_PWR_UP 0x0003 /* ARM(exe/snd) -> DSP(exe) */
-#define DSP_PWR_DOWN 0x0004 /* ARM(exe) <- DSP(req) */
-#define DVFS_START 0x0006 /* ARM(req) <-> DSP(exe/ack)*/
-#define DVFS_STOP 0x0007 /* ARM(req) -> DSP(exe) */
-
-#define TDEL_SAFE 0x0000
-#define TDEL_KILL 0x0001
-
-#define DSPCFG_REQ 0x00
-#define DSPCFG_SYSADRH 0x28
-#define DSPCFG_SYSADRL 0x29
-#define DSPCFG_PROTREV 0x70
-#define DSPCFG_ABORT 0x78
-#define DSPCFG_LAST 0x80
-
-#define REGRW_MEMR 0x00
-#define REGRW_MEMW 0x01
-#define REGRW_IOR 0x02
-#define REGRW_IOW 0x03
-#define REGRW_DATA 0x04
-
-#define VARID_ICRMASK 0x00
-#define VARID_LOADINFO 0x01
-
-#define TTYP_ARCV 0x0001
-#define TTYP_ASND 0x0002
-#define TTYP_BKMD 0x0004
-#define TTYP_BKDM 0x0008
-#define TTYP_PVMD 0x0010
-#define TTYP_PVDM 0x0020
-
-#define EID_BADTID 0x10
-#define EID_BADTCN 0x11
-#define EID_BADBID 0x20
-#define EID_BADCNT 0x21
-#define EID_NOTLOCKED 0x22
-#define EID_STVBUF 0x23
-#define EID_BADADR 0x24
-#define EID_BADTCTL 0x30
-#define EID_BADPARAM 0x50
-#define EID_FATAL 0x58
-#define EID_NOMEM 0xc0
-#define EID_NORES 0xc1
-#define EID_IPBFULL 0xc2
-#define EID_WDT 0xd0
-#define EID_TASKNOTRDY 0xe0
-#define EID_TASKBSY 0xe1
-#define EID_TASKERR 0xef
-#define EID_BADCFGTYP 0xf0
-#define EID_DEBUG 0xf8
-#define EID_BADSEQ 0xfe
-#define EID_BADCMD 0xff
-
-#define TNM_LEN 16
-
-#define TID_FREE 0xff
-#define TID_ANON 0xfe
-
-#define BID_NULL 0xffff
-#define BID_PVT 0xfffe
-
-#endif /* __PLAT_OMAP_DSP_MBCMD_H */
diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c
deleted file mode 100644
index ca87a3a..0000000
--- a/arch/arm/plat-omap/dsp/dsp_mem.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * Conversion to mempool API and ARM MMU section mapping
- * by Paul Mundt <paul.mundt@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/fb.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mempool.h>
-#include <linux/clk.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/arch/tc.h>
-#include <asm/arch/omapfb.h>
-#include <asm/arch/dsp.h>
-#include <asm/arch/mailbox.h>
-#include <asm/arch/mmu.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-#include "ipbuf.h"
-
-#if defined(CONFIG_ARCH_OMAP1)
-#include "../../mach-omap1/mmu.h"
-#elif defined(CONFIG_ARCH_OMAP2)
-#include "../../mach-omap2/mmu.h"
-#endif
-
-#include "mmu.h"
-
-static struct mem_sync_struct mem_sync;
-
-int dsp_mem_sync_inc(void)
-{
- if (dsp_mem_enable((void *)dspmem_base) < 0)
- return -1;
- 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_disable((void *)dspmem_base);
-
- return 0;
-}
-
-/*
- * dsp_mem_sync_config() is called from mbox1 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;
-}
-
-
-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(&dsp_mmu.exmap_sem);
- if (exmap_valid(&dsp_mmu, vadr, len))
- ret = MEM_TYPE_EXTERN;
- else
- ret = MEM_TYPE_NONE;
- up_read(&dsp_mmu.exmap_sem);
- return ret;
- }
-}
-
-int dsp_address_validate(void *p, size_t len, char *fmt, ...)
-{
- char s[64];
- va_list args;
-
- if (dsp_mem_type(p, len) > 0)
- return 0;
-
- if (fmt == NULL)
- goto out;
-
- 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 external memory\n"
- "space where no actual memory is mapped)\n", s, p, len);
- out:
- return -1;
-}
-
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
-
-static inline unsigned long lineup_offset(unsigned long adr,
- unsigned long ref,
- unsigned long mask)
-{
- unsigned long newadr;
-
- newadr = (adr & ~mask) | (ref & mask);
- if (newadr < adr)
- newadr += mask + 1;
- return newadr;
-}
-
-/*
- * fb update functions:
- * fbupd_response() is executed by the workqueue.
- * fbupd_cb() is called when fb update is done, in interrupt context.
- * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
- */
-static void fbupd_response(struct work_struct *unused)
-{
- int status;
-
- status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
- if (status == 0)
- return;
-
- /* FIXME: DSP is busy !! */
- printk(KERN_ERR
- "omapdsp:"
- "DSP is busy when trying to send FBCTL:UPD response!\n");
-}
-
-static DECLARE_WORK(fbupd_response_work, fbupd_response);
-
-static void fbupd_cb(void *arg)
-{
- schedule_work(&fbupd_response_work);
-}
-
-void mbox_fbctl_upd(void)
-{
- struct omapfb_update_window win;
- volatile unsigned short *buf = ipbuf_sys_da->d;
-
- if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
- printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
- return;
- }
- win.x = buf[0];
- win.y = buf[1];
- win.width = buf[2];
- win.height = buf[3];
- win.format = buf[4];
- release_ipbuf_pvt(ipbuf_sys_da);
-
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
- if (!omapfb_ready) {
- printk(KERN_WARNING
- "omapdsp: fbupd() called while HWA742 is not ready!\n");
- return;
- }
-#endif
- omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
-}
-
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
-static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
- unsigned long event, void *fbi)
-{
- pr_info("omapfb_notifier_cb(): event = %s\n",
- (event == OMAPFB_EVENT_READY) ? "READY" :
- (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
- if (event == OMAPFB_EVENT_READY)
- omapfb_ready = 1;
- else if (event == OMAPFB_EVENT_DISABLED)
- omapfb_ready = 0;
- return 0;
-}
-#endif
-
-static int dsp_fbexport(dsp_long_t *dspadr)
-{
- dsp_long_t dspadr_actual;
- unsigned long padr_sys, padr, fbsz_sys, fbsz;
- int cnt;
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
- int status;
-#endif
-
- pr_debug( "omapdsp: frame buffer export\n");
-
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
- if (omapfb_nb) {
- printk(KERN_WARNING
- "omapdsp: frame buffer has been exported already!\n");
- return -EBUSY;
- }
-#endif
-
- if (num_registered_fb == 0) {
- pr_info("omapdsp: frame buffer not registered.\n");
- return -EINVAL;
- }
- if (num_registered_fb != 1) {
- pr_info("omapdsp: %d frame buffers found. we use first one.\n",
- num_registered_fb);
- }
- padr_sys = registered_fb[0]->fix.smem_start;
- fbsz_sys = registered_fb[0]->fix.smem_len;
- if (fbsz_sys == 0) {
- printk(KERN_ERR
- "omapdsp: framebuffer doesn't seem to be configured "
- "correctly! (size=0)\n");
- return -EINVAL;
- }
-
- /*
- * align padr and fbsz to 4kB boundary
- * (should be noted to the user afterwards!)
- */
- padr = padr_sys & ~(SZ_4K-1);
- fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
-
- /* line up dspadr offset with padr */
- dspadr_actual =
- (fbsz > SZ_1M) ? lineup_offset(*dspadr, padr, SZ_1M-1) :
- (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
- /* (fbsz > SZ_4KB) ? */ *dspadr;
- if (dspadr_actual != *dspadr)
- pr_debug(
- "omapdsp: actual dspadr for FBEXPORT = %08x\n",
- dspadr_actual);
- *dspadr = dspadr_actual;
-
- cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz,
- EXMAP_TYPE_FB);
- if (cnt < 0) {
- printk(KERN_ERR "omapdsp: exmap failure.\n");
- return cnt;
- }
-
- if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
- printk(KERN_WARNING
-" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
-" !! screen base address or size is not aligned in 4kB: !!\n"
-" !! actual screen adr = %08lx, size = %08lx !!\n"
-" !! exporting adr = %08lx, size = %08lx !!\n"
-" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n"
-" !! Otherwise DSP can corrupt the kernel memory. !!\n"
-" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
- padr_sys, fbsz_sys, padr, fbsz);
- }
-
- /* increase the DMA priority */
- set_emiff_dma_prio(15);
-
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
- omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
- if (omapfb_nb == NULL) {
- printk(KERN_ERR
- "omapdsp: failed to allocate memory for omapfb_nb!\n");
- omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
- return -ENOMEM;
- }
-
- status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
- if (status)
- pr_info("omapfb_register_client(): failure(%d)\n", status);
-#endif
-
- return cnt;
-}
-#else
-void mbox_fbctl_upd(void) { }
-#endif
-
-/* dsp/mem fops: backward compatibility */
-static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- struct bin_attribute attr;
-
- return __omap_mmu_mem_read(&dsp_mmu, &attr,
- (char __user *)buf, *ppos, count);
-}
-
-static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct bin_attribute attr;
-
- return __omap_mmu_mem_write(&dsp_mmu, &attr,
- (char __user *)buf, *ppos, count);
-}
-
-static int dsp_mem_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct omap_dsp_mapinfo mapinfo;
- __u32 size;
-
- switch (cmd) {
- case MEM_IOCTL_MMUINIT:
- if (dsp_mmu.exmap_tbl)
- omap_mmu_unregister(&dsp_mmu);
- dsp_mem_ipi_init();
- return omap_mmu_register(&dsp_mmu);
-
- case MEM_IOCTL_EXMAP:
- if (copy_from_user(&mapinfo, (void __user *)arg,
- sizeof(mapinfo)))
- return -EFAULT;
- return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
- 0, mapinfo.size, EXMAP_TYPE_MEM);
-
- case MEM_IOCTL_EXUNMAP:
- return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
-
- case MEM_IOCTL_EXMAP_FLUSH:
- omap_mmu_exmap_flush(&dsp_mmu);
- return 0;
-#ifdef CONFIG_OMAP_DSP_FBEXPORT
- case MEM_IOCTL_FBEXPORT:
- {
- dsp_long_t dspadr;
- int ret;
- if (copy_from_user(&dspadr, (void __user *)arg,
- sizeof(dsp_long_t)))
- return -EFAULT;
- ret = dsp_fbexport(&dspadr);
- if (copy_to_user((void __user *)arg, &dspadr,
- sizeof(dsp_long_t)))
- return -EFAULT;
- return ret;
- }
-#endif
- case MEM_IOCTL_MMUITACK:
- return dsp_mmu_itack();
-
- case MEM_IOCTL_KMEM_RESERVE:
-
- if (copy_from_user(&size, (void __user *)arg,
- sizeof(__u32)))
- return -EFAULT;
- return omap_mmu_kmem_reserve(&dsp_mmu, size);
-
-
- case MEM_IOCTL_KMEM_RELEASE:
- omap_mmu_kmem_release();
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-struct file_operations dsp_mem_fops = {
- .owner = THIS_MODULE,
- .read = dsp_mem_read,
- .write = dsp_mem_write,
- .ioctl = dsp_mem_ioctl,
-};
-
-void dsp_mem_start(void)
-{
- 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();
-}
-
-static void dsp_mmu_irq_work(struct work_struct *work)
-{
- struct omap_mmu *mmu = container_of(work, struct omap_mmu, irq_work);
-
- if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
- dsp_err_set(ERRCODE_MMU, mmu->fault_address);
- return;
- }
- omap_mmu_itack(mmu);
- pr_info("Resetting DSP...\n");
- dsp_cpustat_request(CPUSTAT_RESET);
- omap_mmu_enable(mmu, 0);
-}
-
-/*
- * later half of dsp memory initialization
- */
-int dsp_mem_late_init(void)
-{
- int ret;
-
- dsp_mem_ipi_init();
-
- INIT_WORK(&dsp_mmu.irq_work, dsp_mmu_irq_work);
- ret = omap_mmu_register(&dsp_mmu);
- if (ret) {
- dsp_reset_idle_boot_base();
- goto out;
- }
- omap_dsp->mmu = &dsp_mmu;
- out:
- return ret;
-}
-
-int __init dsp_mem_init(void)
-{
-#ifdef CONFIG_ARCH_OMAP2
- dsp_mmu.clk = dsp_fck_handle;
- dsp_mmu.memclk = dsp_ick_handle;
-#elif defined(CONFIG_ARCH_OMAP1)
- dsp_mmu.clk = dsp_ck_handle;
- dsp_mmu.memclk = api_ck_handle;
-#endif
- return 0;
-}
-
-void dsp_mem_exit(void)
-{
- dsp_reset_idle_boot_base();
- omap_mmu_unregister(&dsp_mmu);
-}
diff --git a/arch/arm/plat-omap/dsp/error.c b/arch/arm/plat-omap/dsp/error.c
deleted file mode 100644
index d2276f9..0000000
--- a/arch/arm/plat-omap/dsp/error.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/arch/mailbox.h>
-#include <asm/uaccess.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-
-/*
- * value seen through read()
- */
-#define DSP_ERR_WDT 0x00000001
-#define DSP_ERR_MMU 0x00000002
-static unsigned long errval;
-
-static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
-static int errcnt;
-static u16 wdtval; /* FIXME: read through ioctl */
-static u32 mmu_fadr; /* FIXME: read through ioctl */
-
-/*
- * DSP error detection device file operations
- */
-static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- unsigned long flags;
- int status;
- DEFINE_WAIT(wait);
-
- if (count < 4)
- return 0;
-
- prepare_to_wait(&err_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (errcnt == 0)
- schedule();
- finish_wait(&err_wait_q, &wait);
- if (signal_pending(current))
- return -EINTR;
-
- local_irq_save(flags);
- status = copy_to_user(buf, &errval, 4);
- if (status) {
- local_irq_restore(flags);
- return -EFAULT;
- }
- errcnt = 0;
- local_irq_restore(flags);
-
- return 4;
-}
-
-static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
-{
- unsigned int mask = 0;
-
- poll_wait(file, &err_wait_q, wait);
- if (errcnt != 0)
- mask |= POLLIN | POLLRDNORM;
-
- return mask;
-}
-
-struct file_operations dsp_err_fops = {
- .owner = THIS_MODULE,
- .poll = dsp_err_poll,
- .read = dsp_err_read,
-};
-
-/*
- * set / clear functions
- */
-
-/* DSP MMU */
-static void dsp_err_mmu_set(unsigned long arg)
-{
- disable_irq(omap_dsp->mmu->irq);
- mmu_fadr = (u32)arg;
-}
-
-static void dsp_err_mmu_clr(void)
-{
- enable_irq(omap_dsp->mmu->irq);
-}
-
-/* WDT */
-static void dsp_err_wdt_set(unsigned long arg)
-{
- wdtval = (u16)arg;
-}
-
-/*
- * error code handler
- */
-static struct {
- unsigned long val;
- void (*set)(unsigned long arg);
- void (*clr)(void);
-} dsp_err_desc[ERRCODE_MAX] = {
- [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
- [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
-};
-
-void dsp_err_set(enum errcode_e code, unsigned long arg)
-{
- if (dsp_err_desc[code].set != NULL)
- dsp_err_desc[code].set(arg);
-
- errval |= dsp_err_desc[code].val;
- errcnt++;
- wake_up_interruptible(&err_wait_q);
-}
-
-void dsp_err_clear(enum errcode_e code)
-{
- errval &= ~dsp_err_desc[code].val;
-
- if (dsp_err_desc[code].clr != NULL)
- dsp_err_desc[code].clr();
-}
-
-int dsp_err_isset(enum errcode_e code)
-{
- return (errval & dsp_err_desc[code].val) ? 1 : 0;
-}
-
-void dsp_err_notify(void)
-{
- /* new error code should be assigned */
- dsp_err_set(DSP_ERR_WDT, 0);
-}
-
-/*
- * functions called from mailbox interrupt routine
- */
-static void mbox_err_wdt(u16 data)
-{
- dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
-}
-
-#ifdef OLD_BINARY_SUPPORT
-/* v3.3 obsolete */
-void mbox_wdt(struct mbcmd *mb)
-{
- mbox_err_wdt(mb->data);
-}
-#endif
-
-extern void mbox_err_ipbfull(void);
-extern void mbox_err_fatal(u8 tid);
-
-void mbox_err(struct mbcmd *mb)
-{
- u8 eid = mb->cmd_l;
- char *eidnm = subcmd_name(mb);
- u8 tid;
-
- if (eidnm) {
- printk(KERN_WARNING
- "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
- } else {
- printk(KERN_WARNING
- "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
- eid, mb->data);
- }
-
- switch (eid) {
- case EID_IPBFULL:
- mbox_err_ipbfull();
- break;
-
- case EID_FATAL:
- tid = mb->data & 0x00ff;
- mbox_err_fatal(tid);
- break;
-
- case EID_WDT:
- mbox_err_wdt(mb->data);
- break;
- }
-}
-
-/*
- *
- */
-void dsp_err_start(void)
-{
- enum errcode_e i;
-
- for (i = 0; i < ERRCODE_MAX; i++) {
- if (dsp_err_isset(i))
- dsp_err_clear(i);
- }
- omap_dsp->mbox->err_notify = dsp_err_notify;
- errcnt = 0;
-}
-
-void dsp_err_stop(void)
-{
- wake_up_interruptible(&err_wait_q);
- omap_dsp->mbox->err_notify = NULL;
-}
diff --git a/arch/arm/plat-omap/dsp/hardware_dsp.h b/arch/arm/plat-omap/dsp/hardware_dsp.h
deleted file mode 100644
index 5af46f8..0000000
--- a/arch/arm/plat-omap/dsp/hardware_dsp.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_DSP_HARDWARE_DSP_H
-#define __OMAP_DSP_HARDWARE_DSP_H
-
-#ifdef CONFIG_ARCH_OMAP1
-#include "omap1_dsp.h"
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3430)
-#include "omap2_dsp.h"
-#endif
-
-#endif /* __OMAP_DSP_HARDWARE_DSP_H */
diff --git a/arch/arm/plat-omap/dsp/ipbuf.c b/arch/arm/plat-omap/dsp/ipbuf.c
deleted file mode 100644
index aba8e74..0000000
--- a/arch/arm/plat-omap/dsp/ipbuf.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/sched.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <asm/arch/mailbox.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-#include "ipbuf.h"
-
-static struct ipbuf_head *g_ipbuf;
-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;
-
-static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
-
-void ipbuf_stop(void)
-{
- int i;
-
- device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
-
- spin_lock(&ipb_free.lock);
- RESET_IPBLINK(&ipb_free);
- spin_unlock(&ipb_free.lock);
-
- ipbcfg.ln = 0;
- if (g_ipbuf) {
- kfree(g_ipbuf);
- g_ipbuf = NULL;
- }
- for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
- dsp_mem_disable((void *)daram_base);
- }
- ipbuf_sys_hold_mem_active = 0;
-}
-
-int ipbuf_config(u16 ln, u16 lsz, void *base)
-{
- size_t lsz_byte = ((size_t)lsz) << 1;
- size_t size;
- int ret = 0;
- int i;
-
- /*
- * global IPBUF
- */
- if (((unsigned long)base) & 0x3) {
- printk(KERN_ERR
- "omapdsp: global ipbuf address(0x%p) is not "
- "32-bit aligned!\n", base);
- return -EINVAL;
- }
- size = lsz_byte * ln;
- if (dsp_address_validate(base, size, "global ipbuf") < 0)
- return -EINVAL;
-
- g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
- if (g_ipbuf == NULL) {
- printk(KERN_ERR
- "omapdsp: memory allocation for ipbuf failed.\n");
- return -ENOMEM;
- }
- for (i = 0; i < ln; i++) {
- void *top, *btm;
-
- top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
- btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
- g_ipbuf[i].p = (struct ipbuf *)top;
- g_ipbuf[i].bid = i;
- if (((unsigned long)top & 0xfffe0000) !=
- ((unsigned long)btm & 0xfffe0000)) {
- /*
- * an ipbuf line should not cross
- * 64k-word boundary.
- */
- printk(KERN_ERR
- "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
- " @0x%p, size=0x%08x\n", i, top, lsz_byte);
- ret = -EINVAL;
- goto free_out;
- }
- }
- ipbcfg.ln = ln;
- ipbcfg.lsz = lsz;
- ipbcfg.base = base;
- ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
- ipbcfg.cnt_full = 0;
-
- pr_info("omapdsp: IPBUF configuration\n"
- " %d words * %d lines at 0x%p.\n",
- ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
-
- ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
- if (ret)
- printk(KERN_ERR "device_create_file failed: %d\n", ret);
-
- return ret;
-
- free_out:
- kfree(g_ipbuf);
- g_ipbuf = NULL;
- return ret;
-}
-
-int ipbuf_sys_config(void *p, arm_dsp_dir_t 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, arm_dsp_dir_t 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);
-}
-
-/*
- * Global IPBUF operations
- */
-struct ipbuf_head *bid_to_ipbuf(u16 bid)
-{
- return &g_ipbuf[bid];
-}
-
-struct ipbuf_head *get_free_ipbuf(u8 tid)
-{
- struct ipbuf_head *ipb_h;
-
- if (dsp_mem_enable_ipbuf() < 0)
- return NULL;
-
- spin_lock(&ipb_free.lock);
-
- if (ipblink_empty(&ipb_free)) {
- /* FIXME: wait on queue when not available. */
- ipb_h = NULL;
- goto out;
- }
- ipb_h = &g_ipbuf[ipb_free.top];
- ipb_h->p->la = tid; /* lock */
- __ipblink_del_top(&ipb_free);
-out:
- spin_unlock(&ipb_free.lock);
- dsp_mem_disable_ipbuf();
-
- return ipb_h;
-}
-
-void release_ipbuf(struct ipbuf_head *ipb_h)
-{
- if (ipb_h->p->la == TID_FREE) {
- printk(KERN_WARNING
- "omapdsp: attempt to release unlocked IPBUF[%d].\n",
- ipb_h->bid);
- /*
- * FIXME: re-calc bsycnt
- */
- return;
- }
- ipb_h->p->la = TID_FREE;
- ipb_h->p->sa = TID_FREE;
- ipblink_add_tail(&ipb_free, ipb_h->bid);
-}
-
-static int try_yld(struct ipbuf_head *ipb_h)
-{
- int status;
-
- ipb_h->p->sa = TID_ANON;
- status = mbcompose_send(BKYLD, 0, ipb_h->bid);
- if (status < 0) {
- /* DSP is busy and ARM keeps this line. */
- release_ipbuf(ipb_h);
- return status;
- }
-
- ipb_bsycnt_inc(&ipbcfg);
- return 0;
-}
-
-/*
- * balancing ipbuf lines with DSP
- */
-static void do_balance_ipbuf(struct work_struct *unused)
-{
- while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
- struct ipbuf_head *ipb_h;
-
- if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
- return;
- if (try_yld(ipb_h) < 0)
- return;
- }
-}
-
-static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
-
-void balance_ipbuf(void)
-{
- schedule_work(&balance_ipbuf_work);
-}
-
-/* for process context */
-void unuse_ipbuf(struct ipbuf_head *ipb_h)
-{
- if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
- /* we don't have enough IPBUF lines. let's keep it. */
- release_ipbuf(ipb_h);
- } else {
- /* we have enough IPBUF lines. let's return this line to DSP. */
- ipb_h->p->la = TID_ANON;
- try_yld(ipb_h);
- balance_ipbuf();
- }
-}
-
-/* for interrupt context */
-void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
-{
- release_ipbuf(ipb_h);
- balance_ipbuf();
-}
-
-/*
- * functions called from mailbox interrupt routine
- */
-
-void mbox_err_ipbfull(void)
-{
- ipbcfg.cnt_full++;
-}
-
-/*
- * sysfs files
- */
-static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int len = 0;
- u16 bid;
-
- for (bid = 0; bid < ipbcfg.ln; bid++) {
- struct ipbuf_head *ipb_h = &g_ipbuf[bid];
- u16 la = ipb_h->p->la;
- u16 ld = ipb_h->p->ld;
- u16 c = ipb_h->p->c;
-
- if (len > PAGE_SIZE - 100) {
- len += sprintf(buf + len, "out of buffer.\n");
- goto finish;
- }
-
- len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
- bid, ipb_h->p);
- if (la == TID_FREE) {
- len += sprintf(buf + len,
- " DSPtask[%d]->Linux "
- "(already read and now free for Linux)\n",
- ld);
- } else if (ld == TID_FREE) {
- len += sprintf(buf + len,
- " Linux->DSPtask[%d] "
- "(already read and now free for DSP)\n",
- la);
- } else if (ipbuf_is_held(ld, bid)) {
- len += sprintf(buf + len,
- " DSPtask[%d]->Linux "
- "(waiting to be read)\n"
- " count = %d\n", ld, c);
- } else {
- len += sprintf(buf + len,
- " Linux->DSPtask[%d] "
- "(waiting to be read)\n"
- " count = %d\n", la, c);
- }
- }
-
- len += sprintf(buf + len, "\nFree IPBUF link: ");
- spin_lock(&ipb_free.lock);
- ipblink_for_each(bid, &ipb_free) {
- len += sprintf(buf + len, "%d ", bid);
- }
- spin_unlock(&ipb_free.lock);
- len += sprintf(buf + len, "\n");
- len += sprintf(buf + len, "IPBFULL error count: %ld\n",
- ipbcfg.cnt_full);
-
-finish:
- return len;
-}
diff --git a/arch/arm/plat-omap/dsp/ipbuf.h b/arch/arm/plat-omap/dsp/ipbuf.h
deleted file mode 100644
index 926d353..0000000
--- a/arch/arm/plat-omap/dsp/ipbuf.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __PLAT_OMAP_DSP_IPBUF_H
-#define __PLAT_OMAP_DSP_IPBUF_H
-
-struct ipbuf {
- u16 c; /* count */
- u16 next; /* link */
- u16 la; /* lock owner (ARM side) */
- u16 sa; /* sync word (ARM->DSP) */
- u16 ld; /* lock owner (DSP side) */
- u16 sd; /* sync word (DSP->ARM) */
- unsigned char d[0]; /* data */
-};
-
-struct ipbuf_p {
- u16 c; /* count */
- u16 s; /* sync word */
- u16 al; /* data address lower */
- u16 ah; /* data address upper */
-};
-
-#define IPBUF_SYS_DLEN 31
-
-struct ipbuf_sys {
- u16 s; /* sync word */
- u16 d[IPBUF_SYS_DLEN]; /* data */
-};
-
-struct ipbcfg {
- u16 ln;
- u16 lsz;
- void *base;
- u16 bsycnt;
- unsigned long cnt_full; /* count of IPBFULL error */
-};
-
-struct ipbuf_head {
- u16 bid;
- struct ipbuf *p;
-};
-
-extern struct ipbcfg ipbcfg;
-extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
-
-#define ipb_bsycnt_inc(ipbcfg) atomic_inc((atomic_t *)&((ipbcfg)->bsycnt))
-#define ipb_bsycnt_dec(ipbcfg) atomic_dec((atomic_t *)&((ipbcfg)->bsycnt))
-
-#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;
- u16 top;
- u16 tail;
-};
-
-#define IPBLINK_INIT { \
- .lock = SPIN_LOCK_UNLOCKED, \
- .top = BID_NULL, \
- .tail = BID_NULL, \
- }
-
-#define INIT_IPBLINK(link) \
- do { \
- spin_lock_init(&(link)->lock); \
- (link)->top = BID_NULL; \
- (link)->tail = BID_NULL; \
- } while(0)
-
-#define RESET_IPBLINK(link) \
- do { \
- (link)->top = BID_NULL; \
- (link)->tail = BID_NULL; \
- } while(0)
-
-#define ipblink_empty(link) ((link)->top == BID_NULL)
-
-static inline void __ipblink_del_top(struct ipblink *link)
-{
- struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
-
- if ((link->top = ipb_h->p->next) == BID_NULL)
- link->tail = BID_NULL;
- else
- ipb_h->p->next = BID_NULL;
-}
-
-static inline void ipblink_del_top(struct ipblink *link)
-{
- spin_lock(&link->lock);
- __ipblink_del_top(link);
- spin_unlock(&link->lock);
-}
-
-static inline void __ipblink_add_tail(struct ipblink *link, u16 bid)
-{
- if (ipblink_empty(link))
- link->top = bid;
- else
- bid_to_ipbuf(link->tail)->p->next = bid;
- link->tail = bid;
-}
-
-static inline void ipblink_add_tail(struct ipblink *link, u16 bid)
-{
- spin_lock(&link->lock);
- __ipblink_add_tail(link, bid);
- spin_unlock(&link->lock);
-}
-
-static inline void __ipblink_flush(struct ipblink *link)
-{
- u16 bid;
-
- while (!ipblink_empty(link)) {
- bid = link->top;
- __ipblink_del_top(link);
- unuse_ipbuf(bid_to_ipbuf(bid));
- }
-}
-
-static inline void ipblink_flush(struct ipblink *link)
-{
- spin_lock(&link->lock);
- __ipblink_flush(link);
- spin_unlock(&link->lock);
-}
-
-static inline void __ipblink_add_pvt(struct ipblink *link)
-{
- link->top = BID_PVT;
- link->tail = BID_PVT;
-}
-
-static inline void ipblink_add_pvt(struct ipblink *link)
-{
- spin_lock(&link->lock);
- __ipblink_add_pvt(link);
- spin_unlock(&link->lock);
-}
-
-static inline void __ipblink_del_pvt(struct ipblink *link)
-{
- link->top = BID_NULL;
- link->tail = BID_NULL;
-}
-
-static inline void ipblink_del_pvt(struct ipblink *link)
-{
- spin_lock(&link->lock);
- __ipblink_del_pvt(link);
- spin_unlock(&link->lock);
-}
-
-static inline void __ipblink_flush_pvt(struct ipblink *link)
-{
- if (!ipblink_empty(link))
- ipblink_del_pvt(link);
-}
-
-static inline void ipblink_flush_pvt(struct ipblink *link)
-{
- spin_lock(&link->lock);
- __ipblink_flush_pvt(link);
- spin_unlock(&link->lock);
-}
-
-#define ipblink_for_each(bid, link) \
- for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
-
-#endif /* __PLAT_OMAP_DSP_IPBUF_H */
diff --git a/arch/arm/plat-omap/dsp/mblog.c b/arch/arm/plat-omap/dsp/mblog.c
deleted file mode 100644
index 2b1e113..0000000
--- a/arch/arm/plat-omap/dsp/mblog.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-#include <asm/arch/mailbox.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-
-char *subcmd_name(struct mbcmd *mb)
-{
- u8 cmd_h = mb->cmd_h;
- u8 cmd_l = mb->cmd_l;
- char *s;
-
- switch (cmd_h) {
- case MBOX_CMD_DSP_RUNLEVEL:
- s = (cmd_l == RUNLEVEL_USER) ? "USER":
- (cmd_l == RUNLEVEL_SUPER) ? "SUPER":
- (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
- NULL;
- break;
- case MBOX_CMD_DSP_PM:
- s = (cmd_l == PM_DISABLE) ? "DISABLE":
- (cmd_l == PM_ENABLE) ? "ENABLE":
- NULL;
- break;
- case MBOX_CMD_DSP_KFUNC:
- s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
- (cmd_l == KFUNC_POWER) ?
- ((mb->data == AUDIO_PWR_UP) ? "PWR AUD /UP":
- (mb->data == AUDIO_PWR_DOWN) ? "PWR AUD /DOWN":
- (mb->data == AUDIO_PWR_DOWN2) ? "PWR AUD /DOWN(2)":
- (mb->data == DSP_PWR_UP) ? "PWR DSP /UP":
- (mb->data == DSP_PWR_DOWN) ? "PWR DSP /DOWN":
- (mb->data == DVFS_START) ? "PWR DVFS/START":
- (mb->data == DVFS_STOP) ? "PWR DVFS/STOP":
- NULL):
-
- NULL;
- break;
- case MBOX_CMD_DSP_DSPCFG:
- {
- u8 cfgc = cmd_l & 0x7f;
- s = (cfgc == DSPCFG_REQ) ? "REQ":
- (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
- (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
- (cfgc == DSPCFG_ABORT) ? "ABORT":
- (cfgc == DSPCFG_PROTREV) ? "PROTREV":
- NULL;
- break;
- }
- case MBOX_CMD_DSP_REGRW:
- s = (cmd_l == REGRW_MEMR) ? "MEMR":
- (cmd_l == REGRW_MEMW) ? "MEMW":
- (cmd_l == REGRW_IOR) ? "IOR":
- (cmd_l == REGRW_IOW) ? "IOW":
- (cmd_l == REGRW_DATA) ? "DATA":
- NULL;
- break;
- case MBOX_CMD_DSP_GETVAR:
- case MBOX_CMD_DSP_SETVAR:
- s = (cmd_l == VARID_ICRMASK) ? "ICRMASK":
- (cmd_l == VARID_LOADINFO) ? "LOADINFO":
- NULL;
- break;
- case MBOX_CMD_DSP_ERR:
- s = (cmd_l == EID_BADTID) ? "BADTID":
- (cmd_l == EID_BADTCN) ? "BADTCN":
- (cmd_l == EID_BADBID) ? "BADBID":
- (cmd_l == EID_BADCNT) ? "BADCNT":
- (cmd_l == EID_NOTLOCKED) ? "NOTLOCKED":
- (cmd_l == EID_STVBUF) ? "STVBUF":
- (cmd_l == EID_BADADR) ? "BADADR":
- (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":
- (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
- (cmd_l == EID_TASKBSY) ? "TASKBSY":
- (cmd_l == EID_TASKERR) ? "TASKERR":
- (cmd_l == EID_BADCFGTYP) ? "BADCFGTYP":
- (cmd_l == EID_DEBUG) ? "DEBUG":
- (cmd_l == EID_BADSEQ) ? "BADSEQ":
- (cmd_l == EID_BADCMD) ? "BADCMD":
- NULL;
- break;
- default:
- s = NULL;
- }
-
- return s;
-}
-
-/* output of show() method should fit to PAGE_SIZE */
-#define MBLOG_DEPTH 64
-
-struct mblogent {
- unsigned long jiffies;
- mbox_msg_t msg;
- arm_dsp_dir_t dir;
-};
-
-static struct {
- spinlock_t lock;
- int wp;
- unsigned long cnt, cnt_ad, cnt_da;
- struct mblogent ent[MBLOG_DEPTH];
-} mblog = {
- .lock = SPIN_LOCK_UNLOCKED,
-};
-
-#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
-static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
-{
- const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
- char *dir_str;
- char *subname;
-
- dir_str = (dir == DIR_A2D) ? "sending " : "receiving";
- switch (ci->cmd_l_type) {
- case CMD_L_TYPE_SUBCMD:
- subname = subcmd_name(mb);
- if (unlikely(!subname))
- subname = "Unknown";
- pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
- dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
- ci->name, subname, mb->data);
- break;
- case CMD_L_TYPE_TID:
- pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
- dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
- ci->name, mb->cmd_l, mb->data);
- break;
- case CMD_L_TYPE_NULL:
- pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
- dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
- ci->name, mb->data);
- break;
- }
-}
-#else
-static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
-#endif
-
-void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
-{
- struct mblogent *ent;
-
- spin_lock(&mblog.lock);
- ent = &mblog.ent[mblog.wp];
- ent->jiffies = jiffies;
- ent->msg = *(mbox_msg_t *)mb;
- ent->dir = dir;
- if (mblog.cnt < 0xffffffff)
- mblog.cnt++;
- switch (dir) {
- case DIR_A2D:
- if (mblog.cnt_ad < 0xffffffff)
- mblog.cnt_ad++;
- break;
- case DIR_D2A:
- if (mblog.cnt_da < 0xffffffff)
- mblog.cnt_da++;
- break;
- }
- if (++mblog.wp == MBLOG_DEPTH)
- mblog.wp = 0;
- spin_unlock(&mblog.lock);
-
- mblog_print_cmd(mb, dir);
-}
-
-/*
- * sysfs file
- */
-static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int len = 0;
- int wp;
- int i;
-
- spin_lock(&mblog.lock);
-
- wp = mblog.wp;
- len += sprintf(buf + len,
- "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
- mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
- if (mblog.cnt == 0)
- goto done;
-
- len += sprintf(buf + len, " ARM->DSP ARM<-DSP\n");
- len += sprintf(buf + len, " jiffies cmd data cmd data\n");
- i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
- do {
- struct mblogent *ent = &mblog.ent[i];
- struct mbcmd *mb = (struct mbcmd *)&ent->msg;
- char *subname;
- struct cmdinfo ci_null = {
- .name = "Unknown",
- .cmd_l_type = CMD_L_TYPE_NULL,
- };
- const struct cmdinfo *ci;
-
- len += sprintf(buf + len,
- (ent->dir == DIR_A2D) ?
- "%08lx %04x %04x ":
- "%08lx %04x %04x ",
- ent->jiffies,
- (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
-
- if ((ci = cmdinfo[mb->cmd_h]) == NULL)
- ci = &ci_null;
-
- switch (ci->cmd_l_type) {
- case CMD_L_TYPE_SUBCMD:
- if ((subname = subcmd_name(mb)) == NULL)
- subname = "Unknown";
- len += sprintf(buf + len, "%s:%s\n",
- ci->name, subname);
- break;
- case CMD_L_TYPE_TID:
- len += sprintf(buf + len, "%s:task %d\n",
- ci->name, mb->cmd_l);
- break;
- case CMD_L_TYPE_NULL:
- len += sprintf(buf + len, "%s\n", ci->name);
- break;
- }
-
- if (++i == MBLOG_DEPTH)
- i = 0;
- } while (i != wp);
-
-done:
- spin_unlock(&mblog.lock);
-
- return len;
-}
-
-static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
-
-void __init mblog_init(void)
-{
- int ret;
-
- ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
- if (ret)
- printk(KERN_ERR "device_create_file failed: %d\n", ret);
-}
-
-void mblog_exit(void)
-{
- device_remove_file(omap_dsp->dev, &dev_attr_mblog);
-}
diff --git a/arch/arm/plat-omap/dsp/mmu.h b/arch/arm/plat-omap/dsp/mmu.h
deleted file mode 100644
index 9d60e9e..0000000
--- a/arch/arm/plat-omap/dsp/mmu.h
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef __PLAT_OMAP_DSP_MMU_H
-#define __PLAT_OMAP_DSP_MMU_H
-
-#ifdef CONFIG_ARCH_OMAP1
-
-#ifdef CONFIG_ARCH_OMAP15XX
-struct omap_mmu dsp_mmu = {
- .name = "mmu:dsp",
- .type = OMAP_MMU_DSP,
- .base = IO_ADDRESS(OMAP1510_DSP_MMU_BASE),
- .membase = OMAP1510_DSP_BASE,
- .memsize = OMAP1510_DSP_SIZE,
- .nr_tlb_entries = 32,
- .addrspace = 24,
- .irq = INT_1510_DSP_MMU,
- .ops = &omap1_mmu_ops,
-};
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-struct omap_mmu dsp_mmu = {
- .name = "mmu:dsp",
- .type = OMAP_MMU_DSP,
- .base = IO_ADDRESS(OMAP16XX_DSP_MMU_BASE),
- .membase = OMAP16XX_DSP_BASE,
- .memsize = OMAP16XX_DSP_SIZE,
- .nr_tlb_entries = 32,
- .addrspace = 24,
- .irq = INT_1610_DSP_MMU,
- .ops = &omap1_mmu_ops,
-};
-#endif
-#else /* OMAP2 */
-struct omap_mmu dsp_mmu = {
- .name = "mmu:dsp",
- .type = OMAP_MMU_DSP,
- .base = DSP_MMU_24XX_VIRT,
- .membase = DSP_MEM_24XX_VIRT,
- .memsize = DSP_MEM_24XX_SIZE,
- .nr_tlb_entries = 32,
- .addrspace = 24,
- .irq = INT_24XX_DSP_MMU,
- .ops = &omap2_mmu_ops,
-};
-
-#define IOMAP_VAL 0x3f
-#endif
-
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
-static struct omapfb_notifier_block *omapfb_nb;
-static int omapfb_ready;
-#endif
-
-/*
- * OMAP1 EMIFF access
- */
-#ifdef CONFIG_ARCH_OMAP1
-#define EMIF_PRIO_LB_MASK 0x0000f000
-#define EMIF_PRIO_LB_SHIFT 12
-#define EMIF_PRIO_DMA_MASK 0x00000f00
-#define EMIF_PRIO_DMA_SHIFT 8
-#define EMIF_PRIO_DSP_MASK 0x00000070
-#define EMIF_PRIO_DSP_SHIFT 4
-#define EMIF_PRIO_MPU_MASK 0x00000007
-#define EMIF_PRIO_MPU_SHIFT 0
-#define set_emiff_dma_prio(prio) \
- do { \
- omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
- ~EMIF_PRIO_DMA_MASK) | \
- ((prio) << EMIF_PRIO_DMA_SHIFT), \
- OMAP_TC_OCPT1_PRIOR); \
- } while(0)
-#else
-#define set_emiff_dma_prio(prio) do { } while (0)
-#endif /* CONFIG_ARCH_OMAP1 */
-
-#ifdef CONFIG_ARCH_OMAP1
-static int dsp_mmu_itack(void)
-{
- unsigned long dspadr;
-
- pr_info("omapdsp: sending DSP MMU interrupt ack.\n");
- if (!dsp_err_isset(ERRCODE_MMU)) {
- printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
- return -EINVAL;
- }
- dspadr = dsp_mmu.fault_address & ~(SZ_4K-1);
- /* FIXME: reserve TLB entry for this */
- omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);
- pr_info("omapdsp: falling into recovery runlevel...\n");
- dsp_set_runlevel(RUNLEVEL_RECOVERY);
- omap_mmu_itack(&dsp_mmu);
- udelay(100);
- omap_mmu_exunmap(&dsp_mmu, dspadr);
- dsp_err_clear(ERRCODE_MMU);
- return 0;
-}
-
-/*
- * 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.
- */
-static int intmem_enable(void)
-{
- int ret = 0;
-
- if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
- ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
-
- return ret;
-}
-
-static void intmem_disable(void) {
- if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
- mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
-}
-#else
-static int intmem_enable(void) { return 0; }
-static void intmem_disable(void) { }
-static int dsp_mmu_itack(void) { return 0; }
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2
-static inline void dsp_mem_ipi_init(void)
-{
- int i, dspmem_pg_count;
- dspmem_pg_count = dspmem_size >> 12;
- for (i = 0; i < dspmem_pg_count; i++) {
- writel(i, DSP_IPI_INDEX);
- writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
- }
- writel(1, DSP_IPI_ENABLE);
- writel(IOMAP_VAL, DSP_IPI_IOMAP);
-}
-#else
-static inline void dsp_mem_ipi_init(void) { }
-#endif
-
-#endif /* __PLAT_OMAP_DSP_MMU_H */
diff --git a/arch/arm/plat-omap/dsp/omap1_dsp.h b/arch/arm/plat-omap/dsp/omap1_dsp.h
deleted file mode 100644
index f4ec73e..0000000
--- a/arch/arm/plat-omap/dsp/omap1_dsp.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_DSP_OMAP1_DSP_H
-#define __OMAP_DSP_OMAP1_DSP_H
-
-#ifdef CONFIG_ARCH_OMAP15XX
-#define OMAP1510_DARAM_BASE (OMAP1510_DSP_BASE + 0x0)
-#define OMAP1510_DARAM_SIZE 0x10000
-#define OMAP1510_SARAM_BASE (OMAP1510_DSP_BASE + 0x10000)
-#define OMAP1510_SARAM_SIZE 0x18000
-#endif
-
-#ifdef CONFIG_ARCH_OMAP16XX
-#define OMAP16XX_DARAM_BASE (OMAP16XX_DSP_BASE + 0x0)
-#define OMAP16XX_DARAM_SIZE 0x10000
-#define OMAP16XX_SARAM_BASE (OMAP16XX_DSP_BASE + 0x10000)
-#define OMAP16XX_SARAM_SIZE 0x18000
-#endif
-
-/*
- * Reset Control
- */
-#define ARM_RSTCT1_SW_RST 0x0008
-#define ARM_RSTCT1_DSP_RST 0x0004
-#define ARM_RSTCT1_DSP_EN 0x0002
-#define ARM_RSTCT1_ARM_RST 0x0001
-
-/*
- * MPUI
- */
-#define MPUI_CTRL_WORDSWAP_MASK 0x00600000
-#define MPUI_CTRL_WORDSWAP_ALL 0x00000000
-#define MPUI_CTRL_WORDSWAP_NONAPI 0x00200000
-#define MPUI_CTRL_WORDSWAP_API 0x00400000
-#define MPUI_CTRL_WORDSWAP_NONE 0x00600000
-#define MPUI_CTRL_AP_MASK 0x001c0000
-#define MPUI_CTRL_AP_MDH 0x00000000
-#define MPUI_CTRL_AP_MHD 0x00040000
-#define MPUI_CTRL_AP_DMH 0x00080000
-#define MPUI_CTRL_AP_HMD 0x000c0000
-#define MPUI_CTRL_AP_DHM 0x00100000
-#define MPUI_CTRL_AP_HDM 0x00140000
-#define MPUI_CTRL_BYTESWAP_MASK 0x00030000
-#define MPUI_CTRL_BYTESWAP_NONE 0x00000000
-#define MPUI_CTRL_BYTESWAP_NONAPI 0x00010000
-#define MPUI_CTRL_BYTESWAP_ALL 0x00020000
-#define MPUI_CTRL_BYTESWAP_API 0x00030000
-#define MPUI_CTRL_TIMEOUT_MASK 0x0000ff00
-#define MPUI_CTRL_APIF_HNSTB_DIV_MASK 0x000000f0
-#define MPUI_CTRL_S_NABORT_GL 0x00000008
-#define MPUI_CTRL_S_NABORT_32BIT 0x00000004
-#define MPUI_CTRL_EN_TIMEOUT 0x00000002
-#define MPUI_CTRL_HF_MCUCLK 0x00000001
-#define DSP_BOOT_CONFIG_DIRECT 0x00000000
-#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
-#define DSP_BOOT_CONFIG_IDLE 0x00000002
-#define DSP_BOOT_CONFIG_DL16 0x00000003
-#define DSP_BOOT_CONFIG_DL32 0x00000004
-#define DSP_BOOT_CONFIG_MPUI 0x00000005
-#define DSP_BOOT_CONFIG_INTERNAL 0x00000006
-
-/*
- * DSP boot mode
- * direct: 0xffff00
- * pseudo direct: 0x080000
- * MPUI: branch 0x010000
- * internel: branch 0x024000
- */
-#define DSP_BOOT_ADR_DIRECT 0xffff00
-#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
-#define DSP_BOOT_ADR_MPUI 0x010000
-#define DSP_BOOT_ADR_INTERNAL 0x024000
-
-/*
- * TC
- */
-#define TC_ENDIANISM_SWAP 0x00000002
-#define TC_ENDIANISM_SWAP_WORD 0x00000002
-#define TC_ENDIANISM_SWAP_BYTE 0x00000000
-#define TC_ENDIANISM_EN 0x00000001
-
-/*
- * DSP ICR
- */
-#define DSPREG_ICR_RESERVED_BITS 0xffc0
-#define DSPREG_ICR_EMIF 0x0020
-#define DSPREG_ICR_DPLL 0x0010
-#define DSPREG_ICR_PER 0x0008
-#define DSPREG_ICR_CACHE 0x0004
-#define DSPREG_ICR_DMA 0x0002
-#define DSPREG_ICR_CPU 0x0001
-
-#endif /* __OMAP_DSP_OMAP1_DSP_H */
diff --git a/arch/arm/plat-omap/dsp/omap2_dsp.h b/arch/arm/plat-omap/dsp/omap2_dsp.h
deleted file mode 100644
index 0dc43f0..0000000
--- a/arch/arm/plat-omap/dsp/omap2_dsp.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_DSP_OMAP2_DSP_H
-#define __OMAP_DSP_OMAP2_DSP_H
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP24XX_DARAM_BASE (DSP_MEM_24XX_VIRT + 0x0)
-#define OMAP24XX_DARAM_SIZE 0x10000
-#define OMAP24XX_SARAM_BASE (DSP_MEM_24XX_VIRT + 0x10000)
-#define OMAP24XX_SARAM_SIZE 0x18000
-#endif
-
-#include <asm/arch/hardware.h>
-
-/*
- * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX()
- */
-#ifdef CONFIG_ARCH_OMAP24XX
-#define DSP_IPI_BASE DSP_IPI_24XX_VIRT
-#endif
-
-#ifdef CONFIG_ARCH_OMAP34XX
-#define DSP_IPI_BASE DSP_IPI_34XX_VIRT
-#endif
-
-#define DSP_IPI_REVISION (DSP_IPI_BASE + 0x00)
-#define DSP_IPI_SYSCONFIG (DSP_IPI_BASE + 0x10)
-#define DSP_IPI_INDEX (DSP_IPI_BASE + 0x40)
-#define DSP_IPI_ENTRY (DSP_IPI_BASE + 0x44)
-#define DSP_IPI_ENABLE (DSP_IPI_BASE + 0x48)
-#define DSP_IPI_IOMAP (DSP_IPI_BASE + 0x4c)
-#define DSP_IPI_DSPBOOTCONFIG (DSP_IPI_BASE + 0x50)
-
-#define DSP_IPI_ENTRY_ELMSIZEVALUE_MASK 0x00000003
-#define DSP_IPI_ENTRY_ELMSIZEVALUE_8 0x00000000
-#define DSP_IPI_ENTRY_ELMSIZEVALUE_16 0x00000001
-#define DSP_IPI_ENTRY_ELMSIZEVALUE_32 0x00000002
-
-#define DSP_BOOT_CONFIG_DIRECT 0x00000000
-#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
-#define DSP_BOOT_CONFIG_IDLE 0x00000002
-#define DSP_BOOT_CONFIG_DL16 0x00000003
-#define DSP_BOOT_CONFIG_DL32 0x00000004
-#define DSP_BOOT_CONFIG_API 0x00000005
-#define DSP_BOOT_CONFIG_INTERNAL 0x00000006
-
-/*
- * DSP boot mode
- * direct: 0xffff00
- * pseudo direct: 0x080000
- * API: branch 0x010000
- * internel: branch 0x024000
- */
-#define DSP_BOOT_ADR_DIRECT 0xffff00
-#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
-#define DSP_BOOT_ADR_API 0x010000
-#define DSP_BOOT_ADR_INTERNAL 0x024000
-
-/*
- * DSP ICR
- */
-#define DSPREG_ICR_RESERVED_BITS 0xfc00
-#define DSPREG_ICR_HWA 0x0200
-#define DSPREG_ICR_IPORT 0x0100
-#define DSPREG_ICR_MPORT 0x0080
-#define DSPREG_ICR_XPORT 0x0040
-#define DSPREG_ICR_DPORT 0x0020
-#define DSPREG_ICR_DPLL 0x0010
-#define DSPREG_ICR_PER 0x0008
-#define DSPREG_ICR_CACHE 0x0004
-#define DSPREG_ICR_DMA 0x0002
-#define DSPREG_ICR_CPU 0x0001
-
-#endif /* __OMAP_DSP_OMAP2_DSP_H */
diff --git a/arch/arm/plat-omap/dsp/proclist.h b/arch/arm/plat-omap/dsp/proclist.h
deleted file mode 100644
index 666ca4d..0000000
--- a/arch/arm/plat-omap/dsp/proclist.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __PLAT_OMAP_DSP_PROCLIST_H
-#define __PLAT_OMAP_DSP_PROCLIST_H
-
-struct proc_list {
- struct list_head list_head;
- pid_t pid;
- struct file *file;
-};
-
-static inline int proc_list_add(spinlock_t *lock, struct list_head *list,
- struct task_struct *tsk, struct file *file)
-{
- struct proc_list *new;
-
- new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
- if (new == NULL)
- return -ENOMEM;
- new->pid = tsk->pid;
- new->file = file;
- spin_lock(lock);
- list_add_tail(&new->list_head, list);
- spin_unlock(lock);
-
- return 0;
-}
-
-static inline void proc_list_del(spinlock_t *lock, struct list_head *list,
- struct task_struct *tsk, struct file *file)
-{
- struct proc_list *pl;
-
- spin_lock(lock);
- list_for_each_entry(pl, list, list_head) {
- if (pl->file == file) {
- list_del(&pl->list_head);
- kfree(pl);
- spin_unlock(lock);
- return;
- }
- }
-
- /* correspinding file struct isn't found in the list ??? */
- printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
- "struct file (%p) not found\n", file);
- printk(KERN_ERR "listing proc_list...\n");
- list_for_each_entry(pl, list, list_head)
- printk(KERN_ERR " pid:%d file:%p\n", pl->pid, pl->file);
- spin_unlock(lock);
-}
-
-static inline void proc_list_flush(spinlock_t *lock, struct list_head *list)
-{
- struct proc_list *pl;
-
- spin_lock(lock);
- while (!list_empty(list)) {
- pl = list_entry(list->next, struct proc_list, list_head);
- list_del(&pl->list_head);
- kfree(pl);
- }
- spin_unlock(lock);
-}
-
-#endif /* __PLAT_OMAP_DSP_PROCLIST_H */
diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c
deleted file mode 100644
index e5ee8e0..0000000
--- a/arch/arm/plat-omap/dsp/task.c
+++ /dev/null
@@ -1,3042 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/kfifo.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/arch/mailbox.h>
-#include <asm/arch/dsp.h>
-#include "uaccess_dsp.h"
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-#include "ipbuf.h"
-#include "proclist.h"
-
-/*
- * devstate: task 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.
- * FREEZED: task is attached, but reserved to be killed.
- * ADDFAIL: tadd failed.
- * ADDING: tadd in process.
- * DELING: tdel in process.
- * KILLING: tkill in process.
- */
-#define TASKDEV_ST_NOTASK 0x00000001
-#define TASKDEV_ST_ATTACHED 0x00000002
-#define TASKDEV_ST_GARBAGE 0x00000004
-#define TASKDEV_ST_INVALID 0x00000008
-#define TASKDEV_ST_ADDREQ 0x00000100
-#define TASKDEV_ST_DELREQ 0x00000200
-#define TASKDEV_ST_FREEZED 0x00000400
-#define TASKDEV_ST_ADDFAIL 0x00001000
-#define TASKDEV_ST_ADDING 0x00010000
-#define TASKDEV_ST_DELING 0x00020000
-#define TASKDEV_ST_KILLING 0x00040000
-#define TASKDEV_ST_STATE_MASK 0x7fffffff
-#define TASKDEV_ST_STALE 0x80000000
-
-static struct {
- long state;
- char *name;
-} devstate_desc[] = {
- { TASKDEV_ST_NOTASK, "notask" },
- { TASKDEV_ST_ATTACHED, "attached" },
- { TASKDEV_ST_GARBAGE, "garbage" },
- { TASKDEV_ST_INVALID, "invalid" },
- { TASKDEV_ST_ADDREQ, "addreq" },
- { TASKDEV_ST_DELREQ, "delreq" },
- { TASKDEV_ST_FREEZED, "freezed" },
- { TASKDEV_ST_ADDFAIL, "addfail" },
- { TASKDEV_ST_ADDING, "adding" },
- { TASKDEV_ST_DELING, "deling" },
- { TASKDEV_ST_KILLING, "killing" },
-};
-
-static char *devstate_name(long state)
-{
- int i;
- int max = ARRAY_SIZE(devstate_desc);
-
- for (i = 0; i < max; i++) {
- if (state & devstate_desc[i].state)
- return devstate_desc[i].name;
- }
- return "unknown";
-}
-
-struct rcvdt_bk_struct {
- struct ipblink link;
- unsigned int rp;
-};
-
-struct taskdev {
- struct bus_type *bus;
- struct device dev; /* Generic device interface */
-
- long state;
- struct rw_semaphore state_sem;
- wait_queue_head_t state_wait_q;
- struct mutex usecount_lock;
- unsigned int usecount;
- char name[TNM_LEN];
- struct file_operations fops;
- spinlock_t proc_list_lock;
- struct list_head proc_list;
- struct dsptask *task;
-
- /* read stuff */
- wait_queue_head_t read_wait_q;
- struct mutex read_mutex;
- spinlock_t read_lock;
- union {
- struct kfifo *fifo; /* for active word */
- struct rcvdt_bk_struct bk;
- } rcvdt;
-
- /* write stuff */
- wait_queue_head_t write_wait_q;
- struct mutex write_mutex;
- spinlock_t wsz_lock;
- size_t wsz;
-
- /* tctl stuff */
- wait_queue_head_t tctl_wait_q;
- struct mutex tctl_mutex;
- int tctl_stat;
- int tctl_ret; /* return value for tctl_show() */
-
- /* device lock */
- struct mutex lock;
- pid_t lock_pid;
-};
-
-#define to_taskdev(n) container_of(n, struct taskdev, dev)
-
-struct dsptask {
- enum {
- TASK_ST_ERR = 0,
- TASK_ST_READY,
- TASK_ST_CFGREQ
- } state;
- u8 tid;
- char name[TNM_LEN];
- u16 ttyp;
- struct taskdev *dev;
-
- /* read stuff */
- struct ipbuf_p *ipbuf_pvt_r;
-
- /* write stuff */
- struct ipbuf_p *ipbuf_pvt_w;
-
- /* mmap stuff */
- void *map_base;
- size_t map_length;
-};
-
-#define sndtyp_acv(ttyp) ((ttyp) & TTYP_ASND)
-#define sndtyp_psv(ttyp) (!((ttyp) & TTYP_ASND))
-#define sndtyp_bk(ttyp) ((ttyp) & TTYP_BKDM)
-#define sndtyp_wd(ttyp) (!((ttyp) & TTYP_BKDM))
-#define sndtyp_pvt(ttyp) ((ttyp) & TTYP_PVDM)
-#define sndtyp_gbl(ttyp) (!((ttyp) & TTYP_PVDM))
-#define rcvtyp_acv(ttyp) ((ttyp) & TTYP_ARCV)
-#define rcvtyp_psv(ttyp) (!((ttyp) & TTYP_ARCV))
-#define rcvtyp_bk(ttyp) ((ttyp) & TTYP_BKMD)
-#define rcvtyp_wd(ttyp) (!((ttyp) & TTYP_BKMD))
-#define rcvtyp_pvt(ttyp) ((ttyp) & TTYP_PVMD)
-#define rcvtyp_gbl(ttyp) (!((ttyp) & TTYP_PVMD))
-
-static inline int has_taskdev_lock(struct taskdev *dev);
-static int dsp_rmdev_minor(unsigned char minor);
-static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
-static void taskdev_delete(unsigned char minor);
-static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
-static int dsp_tdel_bh(struct taskdev *dev, u16 type);
-
-static struct bus_type dsptask_bus = {
- .name = "dsptask",
-};
-
-static struct class *dsp_task_class;
-static DEFINE_MUTEX(devmgr_lock);
-static struct taskdev *taskdev[TASKDEV_MAX];
-static struct dsptask *dsptask[TASKDEV_MAX];
-static DEFINE_MUTEX(cfg_lock);
-static u16 cfg_cmd;
-static u8 cfg_tid;
-static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
-static u8 n_task; /* static task count */
-static void *heap;
-
-#define is_dynamic_task(tid) ((tid) >= n_task)
-
-#define devstate_read_lock(dev, devstate) \
- devstate_read_lock_timeout(dev, devstate, 0)
-#define devstate_read_unlock(dev) up_read(&(dev)->state_sem)
-#define devstate_write_lock(dev, devstate) \
- devstate_write_lock_timeout(dev, devstate, 0)
-#define devstate_write_unlock(dev) up_write(&(dev)->state_sem)
-
-static ssize_t devname_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static int fifosz_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count);
-static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
- char *buf);
-static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
- char *buf);
-
-#define __ATTR_RW(_name,_mode) { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
- .show = _name##_show, \
- .store = _name##_store, \
-}
-
-static struct device_attribute dev_attr_devname = __ATTR_RO(devname);
-static struct device_attribute dev_attr_devstate = __ATTR_RO(devstate);
-static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
-static struct device_attribute dev_attr_taskname = __ATTR_RO(taskname);
-static struct device_attribute dev_attr_ttyp = __ATTR_RO(ttyp);
-static struct device_attribute dev_attr_fifosz = __ATTR_RW(fifosz, 0666);
-static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
-static struct device_attribute dev_attr_ipblink = __ATTR_RO(ipblink);
-static struct device_attribute dev_attr_wsz = __ATTR_RO(wsz);
-static struct device_attribute dev_attr_mmap = __ATTR_RO(mmap);
-
-static inline void set_taskdev_state(struct taskdev *dev, int state)
-{
- pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
- dev->name,
- (dev->task ? dev->task->tid : -1),
- devstate_name(dev->state),
- devstate_name(state));
- dev->state = state;
-}
-
-/*
- * devstate_read_lock_timeout()
- * devstate_write_lock_timeout():
- * timeout != 0: dev->state can be diffeent from what you want.
- * timeout == 0: no timeout
- */
-#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw) \
-static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate, \
- int timeout) \
-{ \
- DEFINE_WAIT(wait); \
- down_##rw(&dev->state_sem); \
- while (!(dev->state & devstate)) { \
- up_##rw(&dev->state_sem); \
- prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
- if (!timeout) \
- timeout = MAX_SCHEDULE_TIMEOUT; \
- timeout = schedule_timeout(timeout); \
- finish_wait(&dev->state_wait_q, &wait); \
- if (timeout == 0) \
- return -ETIME; \
- if (signal_pending(current)) \
- return -EINTR; \
- down_##rw(&dev->state_sem); \
- } \
- return 0; \
-}
-BUILD_DEVSTATE_LOCK_TIMEOUT(read)
-BUILD_DEVSTATE_LOCK_TIMEOUT(write)
-
-#define BUILD_DEVSTATE_LOCK_AND_TEST(rw) \
-static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate) \
-{ \
- down_##rw(&dev->state_sem); \
- if (dev->state & devstate) \
- return 1; /* success */ \
- /* failure */ \
- up_##rw(&dev->state_sem); \
- return 0; \
-}
-BUILD_DEVSTATE_LOCK_AND_TEST(read)
-BUILD_DEVSTATE_LOCK_AND_TEST(write)
-
-static int taskdev_lock_interruptible(struct taskdev *dev,
- struct mutex *lock)
-{
- int ret;
-
- if (has_taskdev_lock(dev))
- ret = mutex_lock_interruptible(lock);
- else {
- if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
- return ret;
- ret = mutex_lock_interruptible(lock);
- mutex_unlock(&dev->lock);
- }
-
- return ret;
-}
-
-static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
- struct mutex *lock)
-{
- int ret;
-
- if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
- return -ENODEV;
-
- if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
- devstate_read_unlock(dev);
-
- return ret;
-}
-
-static inline void taskdev_unlock_and_stateunlock(struct taskdev *dev,
- struct mutex *lock)
-{
- mutex_unlock(lock);
- devstate_read_unlock(dev);
-}
-
-/*
- * taskdev_flush_buf()
- * must be called under state_lock(ATTACHED) and dev->read_mutex.
- */
-static int taskdev_flush_buf(struct taskdev *dev)
-{
- u16 ttyp = dev->task->ttyp;
-
- if (sndtyp_wd(ttyp)) {
- /* word receiving */
- kfifo_reset(dev->rcvdt.fifo);
- } else {
- /* block receiving */
- struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
-
- if (sndtyp_gbl(ttyp))
- ipblink_flush(&rcvdt->link);
- else {
- ipblink_flush_pvt(&rcvdt->link);
- release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
- }
- }
-
- return 0;
-}
-
-/*
- * taskdev_set_fifosz()
- * must be called under dev->read_mutex.
- */
-static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
-{
- u16 ttyp = dev->task->ttyp;
-
- if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
- printk(KERN_ERR
- "omapdsp: buffer size can be changed only for "
- "active word sending task.\n");
- return -EINVAL;
- }
- if ((sz == 0) || (sz & 1)) {
- printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
- "it must be even and non-zero value.\n", sz);
- return -EINVAL;
- }
-
- if (kfifo_len(dev->rcvdt.fifo)) {
- printk(KERN_ERR "omapdsp: buffer is not empty!\n");
- return -EIO;
- }
-
- kfifo_free(dev->rcvdt.fifo);
- dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
- if (IS_ERR(dev->rcvdt.fifo)) {
- printk(KERN_ERR
- "omapdsp: unable to change receive buffer size. "
- "(%ld bytes for %s)\n", sz, dev->name);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static inline int has_taskdev_lock(struct taskdev *dev)
-{
- return (dev->lock_pid == current->pid);
-}
-
-static int taskdev_lock(struct taskdev *dev)
-{
- if (mutex_lock_interruptible(&dev->lock))
- return -EINTR;
- dev->lock_pid = current->pid;
- return 0;
-}
-
-static int taskdev_unlock(struct taskdev *dev)
-{
- if (!has_taskdev_lock(dev)) {
- printk(KERN_ERR
- "omapdsp: an illegal process attempted to "
- "unlock the dsptask lock!\n");
- return -EINVAL;
- }
- dev->lock_pid = 0;
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int dsp_task_config(struct dsptask *task, u8 tid)
-{
- u16 ttyp;
- int ret;
-
- task->tid = tid;
- dsptask[tid] = task;
-
- /* TCFG request */
- task->state = TASK_ST_CFGREQ;
- if (mutex_lock_interruptible(&cfg_lock)) {
- ret = -EINTR;
- goto fail_out;
- }
- cfg_cmd = MBOX_CMD_DSP_TCFG;
- mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
- cfg_cmd = 0;
- mutex_unlock(&cfg_lock);
-
- if (task->state != TASK_ST_READY) {
- printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
- ret = -EINVAL;
- goto fail_out;
- }
-
- if (strlen(task->name) <= 1)
- sprintf(task->name, "%d", tid);
- pr_info("omapdsp: task %d: name %s\n", tid, task->name);
-
- ttyp = task->ttyp;
-
- /*
- * task info sanity check
- */
-
- /* task type check */
- if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
- 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) &&
- (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
- ret = -EINVAL;
- goto fail_out;
- }
- 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) &&
- ((!ALIGN((unsigned long)task->map_base, PAGE_SIZE)) ||
- (!ALIGN(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;
- }
-
- return 0;
-
-fail_out:
- dsptask[tid] = NULL;
- return ret;
-}
-
-static void dsp_task_init(struct dsptask *task)
-{
- mbcompose_send(TCTL, task->tid, TCTL_TINIT);
-}
-
-int dsp_task_config_all(u8 n)
-{
- int i, ret;
- struct taskdev *devheap;
- struct dsptask *taskheap;
- size_t devheapsz, taskheapsz;
-
- pr_info("omapdsp: found %d task(s)\n", n);
- if (n == 0)
- return 0;
-
- /*
- * reducing kmalloc!
- */
- devheapsz = sizeof(struct taskdev) * n;
- taskheapsz = sizeof(struct dsptask) * n;
- heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
- if (heap == NULL)
- return -ENOMEM;
- devheap = heap;
- taskheap = heap + devheapsz;
-
- n_task = n;
- for (i = 0; i < n; i++) {
- struct taskdev *dev = &devheap[i];
- struct dsptask *task = &taskheap[i];
-
- if ((ret = dsp_task_config(task, i)) < 0)
- return ret;
- if ((ret = taskdev_init(dev, task->name, i)) < 0)
- return ret;
- if ((ret = taskdev_attach_task(dev, task)) < 0)
- return ret;
- dsp_task_init(task);
- pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
- }
-
- return 0;
-}
-
-static void dsp_task_unconfig(struct dsptask *task)
-{
- dsptask[task->tid] = NULL;
-}
-
-void dsp_task_unconfig_all(void)
-{
- unsigned char minor;
- u8 tid;
- struct dsptask *task;
-
- for (minor = 0; minor < n_task; minor++) {
- /*
- * taskdev[minor] can be NULL in case of
- * configuration failure
- */
- if (taskdev[minor])
- taskdev_delete(minor);
- }
- for (; minor < TASKDEV_MAX; minor++) {
- if (taskdev[minor])
- dsp_rmdev_minor(minor);
- }
-
- for (tid = 0; tid < n_task; tid++) {
- /*
- * dsptask[tid] can be NULL in case of
- * configuration failure
- */
- task = dsptask[tid];
- if (task)
- dsp_task_unconfig(task);
- }
- for (; tid < TASKDEV_MAX; tid++) {
- task = dsptask[tid];
- if (task) {
- /*
- * on-demand tasks should be deleted in
- * rmdev_minor(), but just in case.
- */
- dsp_task_unconfig(task);
- kfree(task);
- }
- }
-
- if (heap) {
- kfree(heap);
- heap = NULL;
- }
-
- n_task = 0;
-}
-
-static struct device_driver dsptask_driver = {
- .name = "dsptask",
- .bus = &dsptask_bus,
-};
-
-u8 dsp_task_count(void)
-{
- return n_task;
-}
-
-int dsp_taskmod_busy(void)
-{
- struct taskdev *dev;
- unsigned char minor;
- unsigned int usecount;
-
- for (minor = 0; minor < TASKDEV_MAX; minor++) {
- dev = taskdev[minor];
- if (dev == NULL)
- continue;
- if ((usecount = dev->usecount) > 0) {
- printk("dsp_taskmod_busy(): %s: usecount=%d\n",
- dev->name, usecount);
- return 1;
- }
-/*
- if ((dev->state & (TASKDEV_ST_ADDREQ |
- TASKDEV_ST_DELREQ)) {
-*/
- if (dev->state & TASKDEV_ST_ADDREQ) {
- printk("dsp_taskmod_busy(): %s is in %s\n",
- dev->name, devstate_name(dev->state));
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * DSP task device file operations
- */
-static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- int ret = 0;
- DEFINE_WAIT(wait);
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
-
-
- prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (kfifo_len(dev->rcvdt.fifo) == 0)
- schedule();
- finish_wait(&dev->read_wait_q, &wait);
- if (kfifo_len(dev->rcvdt.fifo) == 0) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
-
- ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
-
- up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- return ret;
-}
-
-static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
- ssize_t ret = 0;
- DEFINE_WAIT(wait);
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- } else if ((int)buf & 0x1) {
- printk(KERN_ERR
- "omapdsp: buf should be word aligned for "
- "dsp_task_read().\n");
- return -EINVAL;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
-
- prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (ipblink_empty(&rcvdt->link))
- schedule();
- finish_wait(&dev->read_wait_q, &wait);
- if (ipblink_empty(&rcvdt->link)) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
- /* copy from delayed IPBUF */
- if (sndtyp_pvt(dev->task->ttyp)) {
- /* private */
- if (!ipblink_empty(&rcvdt->link)) {
- struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
- unsigned char *base, *src;
- size_t bkcnt;
-
- if (dsp_mem_enable(ipbp) < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- 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 = -EINVAL;
- goto pv_out1;
- }
- if (dsp_mem_enable(base) < 0) {
- ret = -EBUSY;
- goto pv_out1;
- }
- src = base + rcvdt->rp;
- if (bkcnt > count) {
- if (copy_to_user_dsp(buf, src, count)) {
- ret = -EFAULT;
- goto pv_out2;
- }
- ret = count;
- rcvdt->rp += count;
- } else {
- if (copy_to_user_dsp(buf, src, bkcnt)) {
- ret = -EFAULT;
- goto pv_out2;
- }
- ret = bkcnt;
- ipblink_del_pvt(&rcvdt->link);
- release_ipbuf_pvt(ipbp);
- rcvdt->rp = 0;
- }
- pv_out2:
- dsp_mem_disable(src);
- pv_out1:
- dsp_mem_disable(ipbp);
- }
- } else {
- /* global */
- if (dsp_mem_enable_ipbuf() < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- while (!ipblink_empty(&rcvdt->link)) {
- unsigned char *src;
- size_t bkcnt;
- struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
-
- src = ipb_h->p->d + rcvdt->rp;
- bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
- if (bkcnt > count) {
- if (copy_to_user_dsp(buf, src, count)) {
- ret = -EFAULT;
- goto gb_out;
- }
- ret += count;
- rcvdt->rp += count;
- break;
- } else {
- if (copy_to_user_dsp(buf, src, bkcnt)) {
- ret = -EFAULT;
- goto gb_out;
- }
- ret += bkcnt;
- buf += bkcnt;
- count -= bkcnt;
- ipblink_del_top(&rcvdt->link);
- unuse_ipbuf(ipb_h);
- rcvdt->rp = 0;
- }
- }
- gb_out:
- dsp_mem_disable_ipbuf();
- }
-
- up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- return ret;
-}
-
-static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- int ret = 0;
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- } else {
- /* force! */
- count = 2;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
-
- mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
-
- if (kfifo_len(dev->rcvdt.fifo) == 0) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
- ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
-
-up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- return ret;
-}
-
-static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
- int ret = 0;
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- } else if ((int)buf & 0x1) {
- printk(KERN_ERR
- "omapdsp: buf should be word aligned for "
- "dsp_task_read().\n");
- return -EINVAL;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
-
- mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
- &dev->read_wait_q);
-
- if (ipblink_empty(&rcvdt->link)) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
- /*
- * We will not receive more than requested count.
- */
- if (sndtyp_pvt(dev->task->ttyp)) {
- /* private */
- struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
- size_t rcvcnt;
- void *src;
-
- if (dsp_mem_enable(ipbp) < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- 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 = -EINVAL;
- goto pv_out1;
- }
- if (dsp_mem_enable(src) < 0) {
- ret = -EBUSY;
- goto pv_out1;
- }
- if (count > rcvcnt)
- count = rcvcnt;
- if (copy_to_user_dsp(buf, src, count)) {
- ret = -EFAULT;
- goto pv_out2;
- }
- ipblink_del_pvt(&rcvdt->link);
- release_ipbuf_pvt(ipbp);
- ret = count;
-pv_out2:
- dsp_mem_disable(src);
-pv_out1:
- dsp_mem_disable(ipbp);
- } else {
- /* global */
- struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
- size_t rcvcnt;
-
- if (dsp_mem_enable_ipbuf() < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
- if (count > rcvcnt)
- count = rcvcnt;
- if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
- ret = -EFAULT;
- goto gb_out;
- }
- ipblink_del_top(&rcvdt->link);
- unuse_ipbuf(ipb_h);
- ret = count;
-gb_out:
- dsp_mem_disable_ipbuf();
- }
-
-up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- return ret;
-}
-
-static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- u16 wd;
- int ret = 0;
- DEFINE_WAIT(wait);
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- } else {
- /* force! */
- count = 2;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
- return -ENODEV;
-
- prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (dev->wsz == 0)
- schedule();
- finish_wait(&dev->write_wait_q, &wait);
- if (dev->wsz == 0) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
- if (copy_from_user(&wd, buf, count)) {
- ret = -EFAULT;
- goto up_out;
- }
-
- spin_lock(&dev->wsz_lock);
- if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
- spin_unlock(&dev->wsz_lock);
- goto up_out;
- }
- ret = count;
- if (rcvtyp_acv(dev->task->ttyp))
- dev->wsz = 0;
- spin_unlock(&dev->wsz_lock);
-
- up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
- return ret;
-}
-
-static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- int ret = 0;
- DEFINE_WAIT(wait);
-
- if (count == 0) {
- return 0;
- } else if (count & 0x1) {
- printk(KERN_ERR
- "omapdsp: odd count is illegal for DSP task device.\n");
- return -EINVAL;
- } else if ((int)buf & 0x1) {
- printk(KERN_ERR
- "omapdsp: buf should be word aligned for "
- "dsp_task_write().\n");
- return -EINVAL;
- }
-
- if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
- return -ENODEV;
-
- prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (dev->wsz == 0)
- schedule();
- finish_wait(&dev->write_wait_q, &wait);
- if (dev->wsz == 0) {
- /* failure */
- if (signal_pending(current))
- ret = -EINTR;
- goto up_out;
- }
-
- if (count > dev->wsz)
- count = dev->wsz;
-
- if (rcvtyp_pvt(dev->task->ttyp)) {
- /* private */
- struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
- unsigned char *dst;
-
- if (dsp_mem_enable(ipbp) < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- dst = MKVIRT(ipbp->ah, ipbp->al);
- if (dsp_address_validate(dst, count, "task %s write buffer",
- dev->task->name) < 0) {
- ret = -EINVAL;
- goto pv_out1;
- }
- if (dsp_mem_enable(dst) < 0) {
- ret = -EBUSY;
- goto pv_out1;
- }
- if (copy_from_user_dsp(dst, buf, count)) {
- ret = -EFAULT;
- goto pv_out2;
- }
- ipbp->c = count/2;
- ipbp->s = dev->task->tid;
- spin_lock(&dev->wsz_lock);
- if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
- if (rcvtyp_acv(dev->task->ttyp))
- dev->wsz = 0;
- ret = count;
- }
- spin_unlock(&dev->wsz_lock);
- pv_out2:
- dsp_mem_disable(dst);
- pv_out1:
- dsp_mem_disable(ipbp);
- } else {
- /* global */
- struct ipbuf_head *ipb_h;
-
- if (dsp_mem_enable_ipbuf() < 0) {
- ret = -EBUSY;
- goto up_out;
- }
- if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
- goto gb_out;
- if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
- release_ipbuf(ipb_h);
- ret = -EFAULT;
- goto gb_out;
- }
- ipb_h->p->c = count/2;
- ipb_h->p->sa = dev->task->tid;
- spin_lock(&dev->wsz_lock);
- if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
- if (rcvtyp_acv(dev->task->ttyp))
- dev->wsz = 0;
- ret = count;
- ipb_bsycnt_inc(&ipbcfg);
- } else
- release_ipbuf(ipb_h);
- spin_unlock(&dev->wsz_lock);
- gb_out:
- dsp_mem_disable_ipbuf();
- }
-
- up_out:
- taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
- return ret;
-}
-
-static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- struct dsptask *task = dev->task;
- unsigned int mask = 0;
-
- if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
- return 0;
- poll_wait(file, &dev->read_wait_q, wait);
- poll_wait(file, &dev->write_wait_q, wait);
- if (sndtyp_psv(task->ttyp) ||
- (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
- (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
- mask |= POLLIN | POLLRDNORM;
- if (dev->wsz)
- mask |= POLLOUT | POLLWRNORM;
- devstate_read_unlock(dev);
-
- return mask;
-}
-
-static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
-{
- int tctl_argc;
- struct mb_exarg mbarg, *mbargp;
- int interactive;
- u8 tid;
- int ret = 0;
-
- if (cmd < 0x8000) {
- /*
- * 0x0000 - 0x7fff
- * system reserved TCTL commands
- */
- switch (cmd) {
- case TCTL_TEN:
- case TCTL_TDIS:
- tctl_argc = 0;
- interactive = 0;
- break;
- default:
- return -EINVAL;
- }
- }
- /*
- * 0x8000 - 0xffff
- * user-defined TCTL commands
- */
- else if (cmd < 0x8100) {
- /* 0x8000-0x80ff: no arg, non-interactive */
- tctl_argc = 0;
- interactive = 0;
- } else if (cmd < 0x8200) {
- /* 0x8100-0x81ff: 1 arg, non-interactive */
- tctl_argc = 1;
- interactive = 0;
- } else if (cmd < 0x9000) {
- /* 0x8200-0x8fff: reserved */
- return -EINVAL;
- } else if (cmd < 0x9100) {
- /* 0x9000-0x90ff: no arg, interactive */
- tctl_argc = 0;
- interactive = 1;
- } else if (cmd < 0x9200) {
- /* 0x9100-0x91ff: 1 arg, interactive */
- tctl_argc = 1;
- interactive = 1;
- } else {
- /* 0x9200-0xffff: reserved */
- return -EINVAL;
- }
-
- /*
- * if argc < 0, use tctl_argc as is.
- * if argc >= 0, check arg count.
- */
- if ((argc >= 0) && (argc != tctl_argc))
- return -EINVAL;
-
- /*
- * issue TCTL
- */
- if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
- return -EINTR;
-
- tid = dev->task->tid;
- if (tctl_argc > 0) {
- mbarg.argc = tctl_argc;
- mbarg.tid = tid;
- mbarg.argv = argv;
- mbargp = &mbarg;
- } else
- mbargp = NULL;
-
- if (interactive) {
- dev->tctl_stat = -EINVAL;
-
- mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
- &dev->tctl_wait_q);
- if (signal_pending(current)) {
- ret = -EINTR;
- goto up_out;
- }
- if ((ret = dev->tctl_stat) < 0) {
- printk(KERN_ERR "omapdsp: TCTL not responding.\n");
- goto up_out;
- }
- } else
- mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
-
-up_out:
- mutex_unlock(&dev->tctl_mutex);
- return ret;
-}
-
-static int dsp_task_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- int ret;
-
- if (cmd < 0x10000) {
- /* issue TCTL */
- u16 mbargv[1];
-
- mbargv[0] = arg & 0xffff;
- return dsp_tctl_issue(dev, cmd, -1, mbargv);
- }
-
- /* non TCTL ioctls */
- switch (cmd) {
-
- case TASK_IOCTL_LOCK:
- ret = taskdev_lock(dev);
- break;
-
- case TASK_IOCTL_UNLOCK:
- ret = taskdev_unlock(dev);
- break;
-
- case TASK_IOCTL_BFLSH:
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
- ret = taskdev_flush_buf(dev);
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- break;
-
- case TASK_IOCTL_SETBSZ:
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
- ret = taskdev_set_fifosz(dev, arg);
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
- break;
-
- case TASK_IOCTL_GETNAME:
- ret = 0;
- if (copy_to_user((void __user *)arg, dev->name,
- strlen(dev->name) + 1))
- ret = -EFAULT;
- break;
-
- default:
- ret = -ENOIOCTLCMD;
-
- }
-
- 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 & TASKDEV_ST_ATTACHED));
- task = dev->task;
- omap_mmu_exmap_use(&dsp_mmu, 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 & TASKDEV_ST_ATTACHED));
- task = dev->task;
- omap_mmu_exmap_unuse(&dsp_mmu, 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_mmap_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
-{
- return NOPAGE_SIGBUS;
-}
-
-static struct vm_operations_struct dsp_task_vm_ops = {
- .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)
-{
- void *tmp_vadr;
- unsigned long tmp_padr, tmp_vmadr, off;
- size_t req_len, tmp_len;
- unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
- struct dsptask *task;
- int ret = 0;
-
- if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
- return -ENODEV;
- task = dev->task;
-
- /*
- * Don't swap this area out
- * Don't dump this area to a core file
- */
- vma->vm_flags |= VM_RESERVED | VM_IO;
-
- /* Do not cache this area */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- req_len = vma->vm_end - vma->vm_start;
- off = vma->vm_pgoff << PAGE_SHIFT;
- tmp_vmadr = vma->vm_start;
- tmp_vadr = task->map_base + off;
- do {
- tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len);
- if (tmp_padr == 0) {
- printk(KERN_ERR
- "omapdsp: task %s: illegal address "
- "for mmap: %p", task->name, tmp_vadr);
- /* partial mapping will be cleared in upper layer */
- ret = -EINVAL;
- goto unlock_out;
- }
- if (tmp_len > req_len)
- tmp_len = req_len;
-
- pr_debug("omapdsp: mmap info: "
- "vmadr = %08lx, padr = %08lx, len = %x\n",
- tmp_vmadr, tmp_padr, tmp_len);
- if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
- tmp_len, vma->vm_page_prot) != 0) {
- printk(KERN_ERR
- "omapdsp: task %s: remap_page_range() failed.\n",
- task->name);
- /* partial mapping will be cleared in upper layer */
- ret = -EINVAL;
- goto unlock_out;
- }
-
- req_len -= tmp_len;
- tmp_vmadr += tmp_len;
- tmp_vadr += tmp_len;
- } while (req_len);
-
- vma->vm_ops = &dsp_task_vm_ops;
- vma->vm_private_data = dev;
- omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start);
-
-unlock_out:
- devstate_read_unlock(dev);
- return ret;
-}
-
-static int dsp_task_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- struct taskdev *dev;
- int ret = 0;
-
- if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
- return -ENODEV;
-
- restart:
- mutex_lock(&dev->usecount_lock);
- down_write(&dev->state_sem);
-
- /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
- switch (dev->state & TASKDEV_ST_STATE_MASK) {
- case TASKDEV_ST_NOTASK:
- break;
- case TASKDEV_ST_ATTACHED:
- goto attached;
-
- case TASKDEV_ST_INVALID:
- up_write(&dev->state_sem);
- mutex_unlock(&dev->usecount_lock);
- return -ENODEV;
-
- case TASKDEV_ST_FREEZED:
- case TASKDEV_ST_KILLING:
- case TASKDEV_ST_GARBAGE:
- case TASKDEV_ST_DELREQ:
- /* on the kill process. wait until it becomes NOTASK. */
- up_write(&dev->state_sem);
- mutex_unlock(&dev->usecount_lock);
- if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
- return -EINTR;
- devstate_write_unlock(dev);
- goto restart;
- }
-
- /* NOTASK */
- set_taskdev_state(dev, TASKDEV_ST_ADDREQ);
- /* wake up twch daemon for tadd */
- dsp_twch_touch();
- up_write(&dev->state_sem);
- if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
- TASKDEV_ST_ADDFAIL) < 0) {
- /* cancelled */
- if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
- mutex_unlock(&dev->usecount_lock);
- /* out of control ??? */
- return -EINTR;
- }
- set_taskdev_state(dev, TASKDEV_ST_NOTASK);
- ret = -EINTR;
- goto change_out;
- }
- if (dev->state & TASKDEV_ST_ADDFAIL) {
- printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
- dev->name);
- ret = -EBUSY;
- set_taskdev_state(dev, TASKDEV_ST_NOTASK);
- goto change_out;
- }
-
- attached:
- ret = proc_list_add(&dev->proc_list_lock,
- &dev->proc_list, current, file);
- if (ret)
- goto out;
-
- dev->usecount++;
- file->f_op = &dev->fops;
- up_write(&dev->state_sem);
- mutex_unlock(&dev->usecount_lock);
-
-#ifdef DSP_PTE_FREE /* not used currently. */
- dsp_map_update(current);
- dsp_cur_users_add(current);
-#endif /* DSP_PTE_FREE */
- return 0;
-
- change_out:
- wake_up_interruptible_all(&dev->state_wait_q);
- out:
- up_write(&dev->state_sem);
- mutex_unlock(&dev->usecount_lock);
- return ret;
-}
-
-static int dsp_task_release(struct inode *inode, struct file *file)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- struct taskdev *dev = taskdev[minor];
-
-#ifdef DSP_PTE_FREE /* not used currently. */
- dsp_cur_users_del(current);
-#endif /* DSP_PTE_FREE */
-
- if (has_taskdev_lock(dev))
- taskdev_unlock(dev);
-
- proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
- mutex_lock(&dev->usecount_lock);
- if (--dev->usecount > 0) {
- /* other processes are using this device. no state change. */
- mutex_unlock(&dev->usecount_lock);
- return 0;
- }
-
- /* usecount == 0 */
- down_write(&dev->state_sem);
-
- /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
- switch (dev->state & TASKDEV_ST_STATE_MASK) {
-
- case TASKDEV_ST_KILLING:
- break;
-
- case TASKDEV_ST_GARBAGE:
- set_taskdev_state(dev, TASKDEV_ST_NOTASK);
- wake_up_interruptible_all(&dev->state_wait_q);
- break;
-
- case TASKDEV_ST_ATTACHED:
- case TASKDEV_ST_FREEZED:
- if (is_dynamic_task(minor)) {
- set_taskdev_state(dev, TASKDEV_ST_DELREQ);
- /* wake up twch daemon for tdel */
- dsp_twch_touch();
- }
- break;
-
- }
-
- up_write(&dev->state_sem);
- mutex_unlock(&dev->usecount_lock);
- return 0;
-}
-
-/*
- * mkdev / rmdev
- */
-int dsp_mkdev(char *name)
-{
- struct taskdev *dev;
- int status;
- unsigned char minor;
- int ret;
-
- if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
- printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&devmgr_lock))
- return -EINTR;
-
- /* naming check */
- for (minor = 0; minor < TASKDEV_MAX; minor++) {
- if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
- printk(KERN_ERR
- "omapdsp: task device name %s is already "
- "in use.\n", name);
- ret = -EINVAL;
- goto out;
- }
- }
-
- /* find free minor number */
- for (minor = n_task; minor < TASKDEV_MAX; minor++) {
- if (taskdev[minor] == NULL)
- goto do_make;
- }
- printk(KERN_ERR "omapdsp: Too many task devices.\n");
- ret = -EBUSY;
- goto out;
-
-do_make:
- if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- if ((status = taskdev_init(dev, name, minor)) < 0) {
- kfree(dev);
- ret = status;
- goto out;
- }
- ret = minor;
-
-out:
- mutex_unlock(&devmgr_lock);
- return ret;
-}
-
-int dsp_rmdev(char *name)
-{
- unsigned char minor;
- int status;
- int ret;
-
- if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
- printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&devmgr_lock))
- return -EINTR;
-
- /* find in dynamic devices */
- for (minor = n_task; minor < TASKDEV_MAX; minor++) {
- if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
- goto do_remove;
- }
-
- /* find in static devices */
- for (minor = 0; minor < n_task; minor++) {
- if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
- printk(KERN_ERR
- "omapdsp: task device %s is static.\n", name);
- ret = -EINVAL;
- goto out;
- }
- }
-
- printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
- return -EINVAL;
-
-do_remove:
- ret = minor;
- if ((status = dsp_rmdev_minor(minor)) < 0)
- ret = status;
-out:
- mutex_unlock(&devmgr_lock);
- return ret;
-}
-
-static int dsp_rmdev_minor(unsigned char minor)
-{
- struct taskdev *dev = taskdev[minor];
-
- while (!down_write_trylock(&dev->state_sem)) {
- down_read(&dev->state_sem);
- if (dev->state & (TASKDEV_ST_ATTACHED |
- TASKDEV_ST_FREEZED)) {
- /*
- * task is working. kill it.
- * ATTACHED -> FREEZED can be changed under
- * down_read of state_sem..
- */
- set_taskdev_state(dev, TASKDEV_ST_FREEZED);
- wake_up_interruptible_all(&dev->read_wait_q);
- wake_up_interruptible_all(&dev->write_wait_q);
- wake_up_interruptible_all(&dev->tctl_wait_q);
- }
- up_read(&dev->state_sem);
- schedule();
- }
-
- switch (dev->state & TASKDEV_ST_STATE_MASK) {
-
- case TASKDEV_ST_NOTASK:
- case TASKDEV_ST_INVALID:
- /* fine */
- goto notask;
-
- case TASKDEV_ST_ATTACHED:
- case TASKDEV_ST_FREEZED:
- /* task is working. kill it. */
- set_taskdev_state(dev, TASKDEV_ST_KILLING);
- up_write(&dev->state_sem);
- dsp_tdel_bh(dev, TDEL_KILL);
- goto invalidate;
-
- case TASKDEV_ST_ADDREQ:
- /* open() is waiting. drain it. */
- set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
- wake_up_interruptible_all(&dev->state_wait_q);
- break;
-
- case TASKDEV_ST_DELREQ:
- /* nobody is waiting. */
- set_taskdev_state(dev, TASKDEV_ST_NOTASK);
- wake_up_interruptible_all(&dev->state_wait_q);
- break;
-
- case TASKDEV_ST_ADDING:
- case TASKDEV_ST_DELING:
- case TASKDEV_ST_KILLING:
- case TASKDEV_ST_GARBAGE:
- case TASKDEV_ST_ADDFAIL:
- /* transient state. wait for a moment. */
- break;
-
- }
-
- up_write(&dev->state_sem);
-
-invalidate:
- /* wait for some time and hope the state is settled */
- devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
- if (!(dev->state & TASKDEV_ST_NOTASK)) {
- printk(KERN_WARNING
- "omapdsp: illegal device state (%s) on rmdev %s.\n",
- devstate_name(dev->state), dev->name);
- }
-notask:
- set_taskdev_state(dev, TASKDEV_ST_INVALID);
- devstate_read_unlock(dev);
-
- taskdev_delete(minor);
- kfree(dev);
-
- return 0;
-}
-
-static struct file_operations dsp_task_fops = {
- .owner = THIS_MODULE,
- .poll = dsp_task_poll,
- .ioctl = dsp_task_ioctl,
- .open = dsp_task_open,
- .release = dsp_task_release,
-};
-
-static void dsptask_dev_release(struct device *dev)
-{
-}
-
-static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
-{
- int ret;
- struct device *task_dev;
-
- taskdev[minor] = dev;
-
- spin_lock_init(&dev->proc_list_lock);
- INIT_LIST_HEAD(&dev->proc_list);
- init_waitqueue_head(&dev->read_wait_q);
- init_waitqueue_head(&dev->write_wait_q);
- init_waitqueue_head(&dev->tctl_wait_q);
- mutex_init(&dev->read_mutex);
- mutex_init(&dev->write_mutex);
- mutex_init(&dev->tctl_mutex);
- mutex_init(&dev->lock);
- spin_lock_init(&dev->wsz_lock);
- dev->tctl_ret = -EINVAL;
- dev->lock_pid = 0;
-
- strncpy(dev->name, name, TNM_LEN);
- dev->name[TNM_LEN-1] = '\0';
- set_taskdev_state(dev, (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK);
- dev->usecount = 0;
- mutex_init(&dev->usecount_lock);
- memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
-
- dev->dev.parent = omap_dsp->dev;
- dev->dev.bus = &dsptask_bus;
- sprintf(dev->dev.bus_id, "dsptask%d", minor);
- dev->dev.release = dsptask_dev_release;
- ret = device_register(&dev->dev);
- if (ret) {
- printk(KERN_ERR "device_register failed: %d\n", ret);
- return ret;
- }
- ret = device_create_file(&dev->dev, &dev_attr_devname);
- if (ret)
- goto fail_create_devname;
- ret = device_create_file(&dev->dev, &dev_attr_devstate);
- if (ret)
- goto fail_create_devstate;
- ret = device_create_file(&dev->dev, &dev_attr_proc_list);
- if (ret)
- goto fail_create_proclist;
-
- task_dev = device_create(dsp_task_class, NULL,
- MKDEV(OMAP_DSP_TASK_MAJOR, minor),
- "dsptask%d", (int)minor);
-
- if (unlikely(IS_ERR(task_dev))) {
- ret = -EINVAL;
- goto fail_create_taskclass;
- }
-
- init_waitqueue_head(&dev->state_wait_q);
- init_rwsem(&dev->state_sem);
-
- return 0;
-
- fail_create_taskclass:
- device_remove_file(&dev->dev, &dev_attr_proc_list);
- fail_create_proclist:
- device_remove_file(&dev->dev, &dev_attr_devstate);
- fail_create_devstate:
- device_remove_file(&dev->dev, &dev_attr_devname);
- fail_create_devname:
- device_unregister(&dev->dev);
- return ret;
-}
-
-static void taskdev_delete(unsigned char minor)
-{
- struct taskdev *dev = taskdev[minor];
-
- if (!dev)
- return;
- 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);
- device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
- device_unregister(&dev->dev);
- proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
- taskdev[minor] = NULL;
-}
-
-static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
-{
- u16 ttyp = task->ttyp;
- int ret;
-
- dev->fops.read =
- sndtyp_acv(ttyp) ?
- sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
- /* sndtyp_bk */ dsp_task_read_bk_acv:
- /* sndtyp_psv */
- sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
- /* sndtyp_bk */ dsp_task_read_bk_psv;
- if (sndtyp_wd(ttyp)) {
- /* word */
- size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
-
- dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
- &dev->read_lock);
- if (IS_ERR(dev->rcvdt.fifo)) {
- printk(KERN_ERR
- "omapdsp: unable to allocate receive buffer. "
- "(%d bytes for %s)\n", fifosz, dev->name);
- return -ENOMEM;
- }
- } else {
- /* block */
- INIT_IPBLINK(&dev->rcvdt.bk.link);
- dev->rcvdt.bk.rp = 0;
- }
-
- dev->fops.write =
- rcvtyp_wd(ttyp) ? dsp_task_write_wd:
- /* rcvbyp_bk */ dsp_task_write_bk;
- dev->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */
- rcvtyp_wd(ttyp) ? 2 : /* passive word */
- ipbcfg.lsz*2; /* passive block */
-
- if (task->map_length)
- dev->fops.mmap = dsp_task_mmap;
-
- ret = device_create_file(&dev->dev, &dev_attr_taskname);
- if (unlikely(ret))
- goto fail_create_taskname;
- ret = device_create_file(&dev->dev, &dev_attr_ttyp);
- if (unlikely(ret))
- goto fail_create_ttyp;
- ret = device_create_file(&dev->dev, &dev_attr_wsz);
- if (unlikely(ret))
- goto fail_create_wsz;
- if (task->map_length) {
- ret = device_create_file(&dev->dev, &dev_attr_mmap);
- if (unlikely(ret))
- goto fail_create_mmap;
- }
- if (sndtyp_wd(ttyp)) {
- ret = device_create_file(&dev->dev, &dev_attr_fifosz);
- if (unlikely(ret))
- goto fail_create_fifosz;
- ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
- if (unlikely(ret))
- goto fail_create_fifocnt;
- } else {
- ret = device_create_file(&dev->dev, &dev_attr_ipblink);
- if (unlikely(ret))
- goto fail_create_ipblink;
- }
-
- dev->task = task;
- task->dev = dev;
-
- return 0;
-
- fail_create_fifocnt:
- device_remove_file(&dev->dev, &dev_attr_fifosz);
- fail_create_ipblink:
- fail_create_fifosz:
- if (task->map_length)
- device_remove_file(&dev->dev, &dev_attr_mmap);
- fail_create_mmap:
- device_remove_file(&dev->dev, &dev_attr_wsz);
- fail_create_wsz:
- device_remove_file(&dev->dev, &dev_attr_ttyp);
- fail_create_ttyp:
- device_remove_file(&dev->dev, &dev_attr_taskname);
- fail_create_taskname:
- if (task->map_length)
- dev->fops.mmap = NULL;
-
- dev->fops.write = NULL;
- dev->wsz = 0;
-
- dev->fops.read = NULL;
- taskdev_flush_buf(dev);
-
- if (sndtyp_wd(ttyp))
- kfifo_free(dev->rcvdt.fifo);
-
- dev->task = NULL;
-
- return ret;
-}
-
-static void taskdev_detach_task(struct taskdev *dev)
-{
- u16 ttyp = dev->task->ttyp;
-
- device_remove_file(&dev->dev, &dev_attr_taskname);
- device_remove_file(&dev->dev, &dev_attr_ttyp);
- if (sndtyp_wd(ttyp)) {
- device_remove_file(&dev->dev, &dev_attr_fifosz);
- device_remove_file(&dev->dev, &dev_attr_fifocnt);
- } else
- device_remove_file(&dev->dev, &dev_attr_ipblink);
- device_remove_file(&dev->dev, &dev_attr_wsz);
- if (dev->task->map_length) {
- device_remove_file(&dev->dev, &dev_attr_mmap);
- dev->fops.mmap = NULL;
- }
-
- dev->fops.read = NULL;
- taskdev_flush_buf(dev);
- if (sndtyp_wd(ttyp))
- kfifo_free(dev->rcvdt.fifo);
-
- dev->fops.write = NULL;
- dev->wsz = 0;
-
- pr_info("omapdsp: taskdev %s disabled.\n", dev->name);
- dev->task = NULL;
-}
-
-/*
- * tadd / tdel / tkill
- */
-static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
-{
- struct dsptask *task;
- struct mb_exarg arg;
- u8 tid, tid_response;
- u16 argv[2];
- int ret = 0;
-
- if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
- printk(KERN_ERR
- "omapdsp: taskdev %s is not requesting for tadd. "
- "(state is %s)\n", dev->name, devstate_name(dev->state));
- return -EINVAL;
- }
- set_taskdev_state(dev, TASKDEV_ST_ADDING);
- devstate_write_unlock(dev);
-
- if (adr == TADD_ABORTADR) {
- /* aborting tadd intentionally */
- pr_info("omapdsp: tadd address is ABORTADR.\n");
- goto fail_out;
- }
- if (adr >= DSPSPACE_SIZE) {
- printk(KERN_ERR
- "omapdsp: illegal address 0x%08x for tadd\n", adr);
- ret = -EINVAL;
- goto fail_out;
- }
-
- adr >>= 1; /* word address */
- argv[0] = adr >> 16; /* addrh */
- argv[1] = adr & 0xffff; /* addrl */
-
- if (mutex_lock_interruptible(&cfg_lock)) {
- ret = -EINTR;
- goto fail_out;
- }
- cfg_tid = TID_ANON;
- cfg_cmd = MBOX_CMD_DSP_TADD;
- arg.tid = TID_ANON;
- arg.argc = 2;
- arg.argv = argv;
-
- if (dsp_mem_sync_inc() < 0) {
- printk(KERN_ERR "omapdsp: memory sync failed!\n");
- ret = -EBUSY;
- goto fail_out;
- }
- mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
-
- tid = cfg_tid;
- cfg_tid = TID_ANON;
- cfg_cmd = 0;
- mutex_unlock(&cfg_lock);
-
- if (tid == TID_ANON) {
- printk(KERN_ERR "omapdsp: tadd failed!\n");
- ret = -EINVAL;
- goto fail_out;
- }
- if ((tid < n_task) || dsptask[tid]) {
- printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
- ret = -EINVAL;
- goto fail_out;
- }
- if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
- ret = -ENOMEM;
- goto del_out;
- }
-
- if ((ret = dsp_task_config(task, tid)) < 0)
- goto free_out;
-
- if (strcmp(dev->name, task->name)) {
- printk(KERN_ERR
- "omapdsp: task name (%s) doesn't match with "
- "device name (%s).\n", task->name, dev->name);
- ret = -EINVAL;
- goto free_out;
- }
-
- if ((ret = taskdev_attach_task(dev, task)) < 0)
- goto free_out;
-
- dsp_task_init(task);
- pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
- set_taskdev_state(dev, TASKDEV_ST_ATTACHED);
- wake_up_interruptible_all(&dev->state_wait_q);
- return 0;
-
-free_out:
- kfree(task);
-
-del_out:
- printk(KERN_ERR "omapdsp: deleting the task...\n");
-
- set_taskdev_state(dev, TASKDEV_ST_DELING);
-
- if (mutex_lock_interruptible(&cfg_lock)) {
- printk(KERN_ERR "omapdsp: aborting tdel process. "
- "DSP side could be corrupted.\n");
- goto fail_out;
- }
- cfg_tid = TID_ANON;
- cfg_cmd = MBOX_CMD_DSP_TDEL;
- mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
- tid_response = cfg_tid;
- cfg_tid = TID_ANON;
- cfg_cmd = 0;
- mutex_unlock(&cfg_lock);
-
- if (tid_response != tid)
- printk(KERN_ERR "omapdsp: tdel failed. "
- "DSP side could be corrupted.\n");
-
-fail_out:
- set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
- wake_up_interruptible_all(&dev->state_wait_q);
- return ret;
-}
-
-int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
-{
- struct taskdev *dev;
- int status;
- int ret;
-
- if (mutex_lock_interruptible(&devmgr_lock))
- return -EINTR;
-
- if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
- printk(KERN_ERR
- "omapdsp: no task device with minor %d\n", minor);
- ret = -EINVAL;
- goto out;
- }
- ret = minor;
- if ((status = dsp_tadd(dev, adr)) < 0)
- ret = status;
-
-out:
- mutex_unlock(&devmgr_lock);
- return ret;
-}
-
-static int dsp_tdel(struct taskdev *dev)
-{
- if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
- printk(KERN_ERR
- "omapdsp: taskdev %s is not requesting for tdel. "
- "(state is %s)\n", dev->name, devstate_name(dev->state));
- return -EINVAL;
- }
- set_taskdev_state(dev, TASKDEV_ST_DELING);
- devstate_write_unlock(dev);
-
- return dsp_tdel_bh(dev, TDEL_SAFE);
-}
-
-int dsp_tdel_minor(unsigned char minor)
-{
- struct taskdev *dev;
- int status;
- int ret;
-
- if (mutex_lock_interruptible(&devmgr_lock))
- return -EINTR;
-
- if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
- printk(KERN_ERR
- "omapdsp: no task device with minor %d\n", minor);
- ret = -EINVAL;
- goto out;
- }
-
- ret = minor;
- if ((status = dsp_tdel(dev)) < 0)
- ret = status;
-
-out:
- mutex_unlock(&devmgr_lock);
- return ret;
-}
-
-static int dsp_tkill(struct taskdev *dev)
-{
- while (!down_write_trylock(&dev->state_sem)) {
- if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
- TASKDEV_ST_FREEZED))) {
- printk(KERN_ERR
- "omapdsp: task has not been attached for "
- "taskdev %s\n", dev->name);
- return -EINVAL;
- }
- /* ATTACHED -> FREEZED can be changed under read semaphore. */
- set_taskdev_state(dev, TASKDEV_ST_FREEZED);
- wake_up_interruptible_all(&dev->read_wait_q);
- wake_up_interruptible_all(&dev->write_wait_q);
- wake_up_interruptible_all(&dev->tctl_wait_q);
- devstate_read_unlock(dev);
- schedule();
- }
-
- if (!(dev->state & (TASKDEV_ST_ATTACHED |
- TASKDEV_ST_FREEZED))) {
- printk(KERN_ERR
- "omapdsp: task has not been attached for taskdev %s\n",
- dev->name);
- devstate_write_unlock(dev);
- return -EINVAL;
- }
- if (!is_dynamic_task(dev->task->tid)) {
- printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
- dev->name);
- devstate_write_unlock(dev);
- return -EINVAL;
- }
- set_taskdev_state(dev, TASKDEV_ST_KILLING);
- devstate_write_unlock(dev);
-
- return dsp_tdel_bh(dev, TDEL_KILL);
-}
-
-int dsp_tkill_minor(unsigned char minor)
-{
- struct taskdev *dev;
- int status;
- int ret;
-
- if (mutex_lock_interruptible(&devmgr_lock))
- return -EINTR;
-
- if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
- printk(KERN_ERR
- "omapdsp: no task device with minor %d\n", minor);
- ret = -EINVAL;
- goto out;
- }
-
- ret = minor;
- if ((status = dsp_tkill(dev)) < 0)
- ret = status;
-
-out:
- mutex_unlock(&devmgr_lock);
- return ret;
-}
-
-static int dsp_tdel_bh(struct taskdev *dev, u16 type)
-{
- struct dsptask *task;
- u8 tid, tid_response;
- int ret = 0;
-
- task = dev->task;
- tid = task->tid;
- if (mutex_lock_interruptible(&cfg_lock)) {
- if (type == TDEL_SAFE) {
- set_taskdev_state(dev, TASKDEV_ST_DELREQ);
- return -EINTR;
- } else {
- tid_response = TID_ANON;
- ret = -EINTR;
- goto detach_out;
- }
- }
- cfg_tid = TID_ANON;
- cfg_cmd = MBOX_CMD_DSP_TDEL;
- mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
- tid_response = cfg_tid;
- cfg_tid = TID_ANON;
- cfg_cmd = 0;
- mutex_unlock(&cfg_lock);
-
-detach_out:
- taskdev_detach_task(dev);
- dsp_task_unconfig(task);
- kfree(task);
-
- if (tid_response != tid) {
- printk(KERN_ERR "omapdsp: %s failed!\n",
- (type == TDEL_SAFE) ? "tdel" : "tkill");
- ret = -EINVAL;
- }
- down_write(&dev->state_sem);
- set_taskdev_state(dev, (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
- TASKDEV_ST_NOTASK);
- wake_up_interruptible_all(&dev->state_wait_q);
- up_write(&dev->state_sem);
-
- return ret;
-}
-
-/*
- * state inquiry
- */
-long taskdev_state_stale(unsigned char minor)
-{
- if (taskdev[minor]) {
- long state = taskdev[minor]->state;
- taskdev[minor]->state |= TASKDEV_ST_STALE;
- return state;
- } else
- return TASKDEV_ST_NOTASK;
-}
-
-/*
- * functions called from mailbox interrupt routine
- */
-void mbox_wdsnd(struct mbcmd *mb)
-{
- unsigned int n;
- u8 tid = mb->cmd_l;
- u16 data = mb->data;
- struct dsptask *task = dsptask[tid];
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
- return;
- }
- if (sndtyp_bk(task->ttyp)) {
- printk(KERN_ERR
- "mbox: WDSND from block sending task! (task%d)\n", tid);
- return;
- }
- if (sndtyp_psv(task->ttyp) &&
- !waitqueue_active(&task->dev->read_wait_q)) {
- printk(KERN_WARNING
- "mbox: WDSND from passive sending task (task%d) "
- "without request!\n", tid);
- return;
- }
-
- n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
- sizeof(data));
- if (n != sizeof(data))
- printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
-
- wake_up_interruptible(&task->dev->read_wait_q);
-}
-
-void mbox_wdreq(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- struct dsptask *task = dsptask[tid];
- struct taskdev *dev;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
- return;
- }
- if (rcvtyp_psv(task->ttyp)) {
- printk(KERN_ERR
- "mbox: WDREQ from passive receiving task! (task%d)\n",
- tid);
- return;
- }
-
- dev = task->dev;
- spin_lock(&dev->wsz_lock);
- dev->wsz = 2;
- spin_unlock(&dev->wsz_lock);
- wake_up_interruptible(&dev->write_wait_q);
-}
-
-void mbox_bksnd(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- u16 bid = mb->data;
- struct dsptask *task = dsptask[tid];
- struct ipbuf_head *ipb_h;
- u16 cnt;
-
- if (bid >= ipbcfg.ln) {
- printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
- return;
- }
- ipb_h = bid_to_ipbuf(bid);
- ipb_bsycnt_dec(&ipbcfg);
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
- goto unuse_ipbuf_out;
- }
- if (sndtyp_wd(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKSND from word sending task! (task%d)\n", tid);
- goto unuse_ipbuf_out;
- }
- if (sndtyp_pvt(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKSND from private sending task! (task%d)\n", tid);
- goto unuse_ipbuf_out;
- }
- if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
- printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
- return;
- }
-
- /* should be done in DSP, but just in case. */
- ipb_h->p->next = BID_NULL;
-
- cnt = ipb_h->p->c;
- if (cnt > ipbcfg.lsz) {
- printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
- cnt, ipbcfg.lsz);
- goto unuse_ipbuf_out;
- }
-
- if (cnt == 0) {
- /* 0-byte send from DSP */
- unuse_ipbuf_nowait(ipb_h);
- goto done;
- }
- ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
- /* we keep coming bid and return alternative line to DSP. */
- balance_ipbuf();
-
-done:
- wake_up_interruptible(&task->dev->read_wait_q);
- return;
-
-unuse_ipbuf_out:
- unuse_ipbuf_nowait(ipb_h);
- return;
-}
-
-void mbox_bkreq(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- u16 cnt = mb->data;
- struct dsptask *task = dsptask[tid];
- struct taskdev *dev;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
- return;
- }
- if (rcvtyp_wd(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQ from word receiving task! (task%d)\n", tid);
- return;
- }
- if (rcvtyp_pvt(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQ from private receiving task! (task%d)\n",
- tid);
- return;
- }
- if (rcvtyp_psv(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQ from passive receiving task! (task%d)\n",
- tid);
- return;
- }
-
- dev = task->dev;
- spin_lock(&dev->wsz_lock);
- dev->wsz = cnt*2;
- spin_unlock(&dev->wsz_lock);
- wake_up_interruptible(&dev->write_wait_q);
-}
-
-void mbox_bkyld(struct mbcmd *mb)
-{
- u16 bid = mb->data;
- struct ipbuf_head *ipb_h;
-
- if (bid >= ipbcfg.ln) {
- printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
- return;
- }
- ipb_h = bid_to_ipbuf(bid);
-
- /* should be done in DSP, but just in case. */
- ipb_h->p->next = BID_NULL;
-
- /* we don't need to sync with DSP */
- ipb_bsycnt_dec(&ipbcfg);
- release_ipbuf(ipb_h);
-}
-
-void mbox_bksndp(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- struct dsptask *task = dsptask[tid];
- struct ipbuf_p *ipbp;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
- return;
- }
- if (sndtyp_wd(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKSNDP from word sending task! (task%d)\n", tid);
- return;
- }
- if (sndtyp_gbl(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKSNDP from non-private sending task! (task%d)\n",
- tid);
- return;
- }
-
- /*
- * we should not have delayed block at this point
- * because read() routine releases the lock of the buffer and
- * until then DSP can't send next data.
- */
-
- ipbp = task->ipbuf_pvt_r;
- if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
- printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
- return;
- }
- pr_debug("mbox: ipbuf_pvt_r->a = 0x%08lx\n",
- MKLONG(ipbp->ah, ipbp->al));
- ipblink_add_pvt(&task->dev->rcvdt.bk.link);
- wake_up_interruptible(&task->dev->read_wait_q);
-}
-
-void mbox_bkreqp(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- struct dsptask *task = dsptask[tid];
- struct taskdev *dev;
- struct ipbuf_p *ipbp;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
- return;
- }
- if (rcvtyp_wd(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQP from word receiving task! (task%d)\n", tid);
- return;
- }
- if (rcvtyp_gbl(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
- return;
- }
- if (rcvtyp_psv(task->ttyp)) {
- printk(KERN_ERR
- "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
- return;
- }
-
- ipbp = task->ipbuf_pvt_w;
- if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
- printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
- return;
- }
- pr_debug("mbox: ipbuf_pvt_w->a = 0x%08lx\n",
- MKLONG(ipbp->ah, ipbp->al));
- dev = task->dev;
- spin_lock(&dev->wsz_lock);
- dev->wsz = ipbp->c*2;
- spin_unlock(&dev->wsz_lock);
- wake_up_interruptible(&dev->write_wait_q);
-}
-
-void mbox_tctl(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- struct dsptask *task = dsptask[tid];
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
- return;
- }
-
- if (!waitqueue_active(&task->dev->tctl_wait_q)) {
- printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
- return;
- }
-
- task->dev->tctl_stat = mb->data;
- wake_up_interruptible(&task->dev->tctl_wait_q);
-}
-
-void mbox_tcfg(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- struct dsptask *task = dsptask[tid];
- u16 *tnm;
- volatile u16 *buf;
- int i;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
- return;
- }
- if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
- printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
- return;
- }
-
- if (dsp_mem_enable(ipbuf_sys_da) < 0) {
- printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
- dsp_mem_disable(ipbuf_sys_da);
- goto out;
- }
- if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
- printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
- dsp_mem_disable(ipbuf_sys_da);
- goto out;
- }
-
- /*
- * read configuration data on system IPBUF
- */
- buf = ipbuf_sys_da->d;
- task->ttyp = buf[0];
- task->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);
- dsp_mem_disable(ipbuf_sys_da);
-
- /*
- * copy task name string
- */
- if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
- task->name[0] = '\0';
- goto out;
- }
-
- for (i = 0; i < TNM_LEN-1; i++) {
- /* avoiding byte access */
- u16 tmp = tnm[i];
- task->name[i] = tmp & 0x00ff;
- if (!tmp)
- break;
- }
- task->name[TNM_LEN-1] = '\0';
-
- task->state = TASK_ST_READY;
-out:
- wake_up_interruptible(&cfg_wait_q);
-}
-
-void mbox_tadd(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
-
- if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
- printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
- return;
- }
- cfg_tid = tid;
- wake_up_interruptible(&cfg_wait_q);
-}
-
-void mbox_tdel(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
-
- if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
- printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
- return;
- }
- cfg_tid = tid;
- wake_up_interruptible(&cfg_wait_q);
-}
-
-void mbox_err_fatal(u8 tid)
-{
- struct dsptask *task = dsptask[tid];
- struct taskdev *dev;
-
- if ((tid >= TASKDEV_MAX) || (task == NULL)) {
- printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
- return;
- }
-
- /* wake up waiting processes */
- dev = task->dev;
- wake_up_interruptible_all(&dev->read_wait_q);
- wake_up_interruptible_all(&dev->write_wait_q);
- wake_up_interruptible_all(&dev->tctl_wait_q);
-}
-
-static u16 *dbg_buf;
-static u16 dbg_buf_sz, dbg_line_sz;
-static int dbg_rp;
-
-int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
-{
-#ifdef OLD_BINARY_SUPPORT
- if ((mbox_revision == MBREV_3_0) || (mbox_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 mbox_dbg_old(struct mbcmd *mb);
-#endif
-
-void mbox_dbg(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- int cnt = mb->data;
- char s[80], *s_end = &s[79], *p;
- u16 *src;
- int i;
-
-#ifdef OLD_BINARY_SUPPORT
- if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
- mbox_dbg_old(mb);
- return;
- }
-#endif
-
- if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
- (tid != TID_ANON)) {
- printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
- return;
- }
- if (dbg_buf == NULL) {
- printk(KERN_ERR "mbox: 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++) {
- u16 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';
- pr_info("%s", s);
- p = s;
- continue;
- }
- if (p == s_end) {
- *p = '\0';
- pr_info("%s\n", s);
- p = s;
- continue;
- }
- }
- if (p > s) {
- *p = '\0';
- pr_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 mbox_dbg_old(struct mbcmd *mb)
-{
- u8 tid = mb->cmd_l;
- char s[80], *s_end = &s[79], *p;
- u16 *src;
- volatile u16 *buf;
- int cnt;
- int i;
-
- if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
- (tid != TID_ANON)) {
- printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
- return;
- }
- if (dsp_mem_enable(ipbuf_sys_da) < 0) {
- printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
- return;
- }
- if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
- printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
- goto out1;
- }
- buf = ipbuf_sys_da->d;
- cnt = buf[0];
- src = MKVIRT(buf[1], buf[2]);
- if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
- goto out2;
-
- if (dsp_mem_enable(src) < 0)
- goto out2;
-
- p = s;
- for (i = 0; i < cnt; i++) {
- u16 tmp;
- /*
- * Be carefull that ipbuf 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';
- pr_info("%s", s);
- p = s;
- continue;
- }
- if (p == s_end) {
- *p = '\0';
- pr_info("%s\n", s);
- p = s;
- continue;
- }
- }
- if (p > s) {
- *p = '\0';
- pr_info("%s\n", s);
- }
-
- dsp_mem_disable(src);
-out2:
- release_ipbuf_pvt(ipbuf_sys_da);
-out1:
- dsp_mem_disable(ipbuf_sys_da);
-}
-#endif /* OLD_BINARY_SUPPORT */
-
-/*
- * sysfs files: for each device
- */
-
-/* devname */
-static ssize_t devname_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", to_taskdev(d)->name);
-}
-
-/* devstate */
-static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
-}
-
-/* proc_list */
-static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct taskdev *dev;
- struct proc_list *pl;
- int len = 0;
-
- dev = to_taskdev(d);
- spin_lock(&dev->proc_list_lock);
- list_for_each_entry(pl, &dev->proc_list, list_head) {
- /* need to lock tasklist_lock before calling
- * find_task_by_pid_type. */
- if (find_task_by_pid(pl->pid) != NULL)
- len += sprintf(buf + len, "%d\n", pl->pid);
- read_unlock(&tasklist_lock);
- }
- spin_unlock(&dev->proc_list_lock);
-
- return len;
-}
-
-/* taskname */
-static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct taskdev *dev = to_taskdev(d);
- int len;
-
- if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
- return -ENODEV;
-
- len = sprintf(buf, "%s\n", dev->task->name);
-
- devstate_read_unlock(dev);
- return len;
-}
-
-/* ttyp */
-static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct taskdev *dev = to_taskdev(d);
- u16 ttyp;
- int len = 0;
-
- if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
- return -ENODEV;
-
- ttyp = dev->task->ttyp;
- len += sprintf(buf + len, "0x%04x\n", ttyp);
- len += sprintf(buf + len, "%s %s send\n",
- (sndtyp_acv(ttyp)) ? "active" :
- "passive",
- (sndtyp_wd(ttyp)) ? "word" :
- (sndtyp_pvt(ttyp)) ? "private block" :
- "global block");
- len += sprintf(buf + len, "%s %s receive\n",
- (rcvtyp_acv(ttyp)) ? "active" :
- "passive",
- (rcvtyp_wd(ttyp)) ? "word" :
- (rcvtyp_pvt(ttyp)) ? "private block" :
- "global block");
-
- devstate_read_unlock(dev);
- return len;
-}
-
-/* fifosz */
-static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
- return sprintf(buf, "%d\n", fifo->size);
-}
-
-static int fifosz_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct taskdev *dev = to_taskdev(d);
- unsigned long fifosz;
- int ret;
-
- fifosz = simple_strtol(buf, NULL, 10);
- if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
- return -ENODEV;
- ret = taskdev_set_fifosz(dev, fifosz);
- taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
-
- return (ret < 0) ? ret : strlen(buf);
-}
-
-/* fifocnt */
-static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
- return sprintf(buf, "%d\n", fifo->size);
-}
-
-/* ipblink */
-static inline char *bid_name(u16 bid)
-{
- static char s[6];
-
- switch (bid) {
- case BID_NULL:
- return "NULL";
- case BID_PVT:
- return "PRIVATE";
- default:
- sprintf(s, "%d", bid);
- return s;
- }
-}
-
-static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
- int len;
-
- spin_lock(&rcvdt->link.lock);
- len = sprintf(buf, "top %s\ntail %s\n",
- bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
- spin_unlock(&rcvdt->link.lock);
-
- return len;
-}
-
-/* wsz */
-static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
-}
-
-/* mmap */
-static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct dsptask *task = to_taskdev(d)->task;
- return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
-}
-
-/*
- * called from ipbuf_show()
- */
-int ipbuf_is_held(u8 tid, u16 bid)
-{
- struct dsptask *task = dsptask[tid];
- struct ipblink *link;
- u16 b;
- int ret = 0;
-
- if (task == NULL)
- return 0;
-
- link = &task->dev->rcvdt.bk.link;
- spin_lock(&link->lock);
- ipblink_for_each(b, link) {
- if (b == bid) { /* found */
- ret = 1;
- break;
- }
- }
- spin_unlock(&link->lock);
-
- return ret;
-}
-
-int __init dsp_taskmod_init(void)
-{
- int retval;
-
- memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
- memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
-
- retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
- &dsp_task_fops);
- if (retval < 0) {
- printk(KERN_ERR
- "omapdsp: failed to register task device: %d\n", retval);
- return retval;
- }
-
- retval = bus_register(&dsptask_bus);
- if (retval) {
- printk(KERN_ERR
- "omapdsp: failed to register DSP task bus: %d\n",
- retval);
- unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
- return -EINVAL;
- }
- retval = driver_register(&dsptask_driver);
- if (retval) {
- printk(KERN_ERR
- "omapdsp: failed to register DSP task driver: %d\n",
- retval);
- bus_unregister(&dsptask_bus);
- unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
- return -EINVAL;
- }
- dsp_task_class = class_create(THIS_MODULE, "dsptask");
- if (IS_ERR(dsp_task_class)) {
- printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
- driver_unregister(&dsptask_driver);
- bus_unregister(&dsptask_bus);
- unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
- return -EINVAL;
- }
-
- return 0;
-}
-
-void dsp_taskmod_exit(void)
-{
- class_destroy(dsp_task_class);
- driver_unregister(&dsptask_driver);
- bus_unregister(&dsptask_bus);
- unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
-}
diff --git a/arch/arm/plat-omap/dsp/taskwatch.c b/arch/arm/plat-omap/dsp/taskwatch.c
deleted file mode 100644
index 4297b51..0000000
--- a/arch/arm/plat-omap/dsp/taskwatch.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-#include <asm/arch/dsp.h>
-#include "dsp_mbcmd.h"
-#include "dsp.h"
-
-static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
-static unsigned int change_cnt;
-
-void dsp_twch_touch(void)
-{
- change_cnt++;
- wake_up_interruptible(&read_wait_q);
-}
-
-/*
- * @count: represents the device counts of the user's interst
- */
-static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- long taskstat[TASKDEV_MAX];
- int devcount = count / sizeof(long);
- int i;
- DEFINE_WAIT(wait);
-
- if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
- printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
- return -EINVAL;
- }
-
- prepare_to_wait(&read_wait_q, &wait, TASK_INTERRUPTIBLE);
- if (change_cnt == 0) /* last check */
- schedule();
- finish_wait(&read_wait_q, &wait);
-
- /* unconfigured while waiting ;-( */
- if ((change_cnt == 0) && (dsp_cfgstat_get_stat() != CFGSTAT_READY))
- return -EINVAL;
-
- if (devcount > TASKDEV_MAX)
- devcount = TASKDEV_MAX;
-
- count = devcount * sizeof(long);
- change_cnt = 0;
- for (i = 0; i < devcount; 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))
- return -EFAULT;
-
- return count;
-}
-
-static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
-{
- unsigned int mask = 0;
-
- poll_wait(file, &read_wait_q, wait);
- if (change_cnt)
- mask |= POLLIN | POLLRDNORM;
-
- return mask;
-}
-
-static int dsp_twch_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- switch (cmd) {
- case TWCH_IOCTL_MKDEV:
- {
- char name[TNM_LEN];
- if (copy_from_user(name, (void __user *)arg, TNM_LEN))
- return -EFAULT;
- name[TNM_LEN-1] = '\0';
- ret = dsp_mkdev(name);
- break;
- }
-
- case TWCH_IOCTL_RMDEV:
- {
- char name[TNM_LEN];
- if (copy_from_user(name, (void __user *)arg, TNM_LEN))
- return -EFAULT;
- name[TNM_LEN-1] = '\0';
- ret = dsp_rmdev(name);
- break;
- }
-
- case TWCH_IOCTL_TADD:
- {
- struct omap_dsp_taddinfo ti;
- if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
- return -EFAULT;
- ret = dsp_tadd_minor(ti.minor, ti.taskadr);
- break;
- }
-
- case TWCH_IOCTL_TDEL:
- ret = dsp_tdel_minor(arg);
- break;
-
- case TWCH_IOCTL_TKILL:
- ret = dsp_tkill_minor(arg);
- break;
-
- default:
- return -ENOIOCTLCMD;
- }
-
- return ret;
-}
-
-struct file_operations dsp_twch_fops = {
- .owner = THIS_MODULE,
- .read = dsp_twch_read,
- .poll = dsp_twch_poll,
- .ioctl = dsp_twch_ioctl,
-};
-
-void dsp_twch_start(void)
-{
- change_cnt = 1; /* first read will not wait */
-}
-
-void dsp_twch_stop(void)
-{
- wake_up_interruptible(&read_wait_q);
-}
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.S b/arch/arm/plat-omap/dsp/uaccess_dsp.S
deleted file mode 100644
index bcf4a54..0000000
--- a/arch/arm/plat-omap/dsp/uaccess_dsp.S
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
- .text
-
-/* Prototype: int __copy_to_user_dsp_2b(void *to, const char *from)
- * Purpose : copy 2 bytes to user memory from kernel(DSP) memory
- * escaping from unexpected byte swap using __copy_to_user()
- * in OMAP architecture.
- * Params : to - user memory
- * : from - kernel(DSP) memory
- * Returns : success = 0, failure = 2
- */
-
-ENTRY(__copy_to_user_dsp_2b)
- stmfd sp!, {r4, lr}
- ldrb r3, [r1], #1
- ldrb r4, [r1], #1
-USER( strbt r4, [r0], #1) @ May fault
-USER( strbt r3, [r0], #1) @ May fault
- mov r0, #0
- ldmfd sp!, {r4, pc}
-
- .section .fixup,"ax"
- .align 0
-9001: mov r0, #2
- ldmfd sp!, {r4, pc}
- .previous
-
-/* Prototype: unsigned long __copy_from_user_dsp_2b(void *to, const void *from);
- * Purpose : copy 2 bytes from user memory to kernel(DSP) memory
- * escaping from unexpected byte swap using __copy_to_user()
- * in OMAP architecture.
- * Params : to - kernel (DSP) memory
- * : from - user memory
- * Returns : success = 0, failure = 2
- */
-
-ENTRY(__copy_from_user_dsp_2b)
- stmfd sp!, {r4, lr}
-USER( ldrbt r3, [r1], #1) @ May fault
-USER( ldrbt r4, [r1], #1) @ May fault
- strb r4, [r0], #1
- strb r3, [r0], #1
- mov r0, #0
- ldmfd sp!, {r4, pc}
-
- .section .fixup,"ax"
- .align 0
-9001: mov r3, #0
- strh r3, [r0], #2
- mov r0, #2
- ldmfd sp!, {r4, pc}
- .previous
diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.h b/arch/arm/plat-omap/dsp/uaccess_dsp.h
deleted file mode 100644
index 028814f..0000000
--- a/arch/arm/plat-omap/dsp/uaccess_dsp.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
- *
- * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef _OMAP_DSP_UACCESS_DSP_H
-#define _OMAP_DSP_UACCESS_DSP_H
-
-#include <asm/uaccess.h>
-#include <asm/arch/dsp_common.h>
-#include "dsp.h"
-
-#define HAVE_ASM_COPY_FROM_USER_DSP_2B
-
-#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
-extern unsigned long __copy_from_user_dsp_2b(void *to,
- const void __user *from);
-extern unsigned long __copy_to_user_dsp_2b(void __user *to,
- const void *from);
-#endif
-
-#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
-static inline unsigned long copy_from_user_dsp_2b(void *to,
- const void *from)
-{
- unsigned short tmp;
-
- if (__copy_from_user(&tmp, from, 2))
- return 2;
- /* expecting compiler to generate "strh" instruction */
- *((unsigned short *)to) = tmp;
- return 0;
-}
-#endif
-
-/*
- * @n must be multiple of 2
- */
-static inline unsigned long copy_from_user_dsp(void *to, const void *from,
- unsigned long n)
-{
- if (access_ok(VERIFY_READ, from, n)) {
- if ((is_dsp_internal_mem(to)) &&
- (((unsigned long)to & 2) || (n & 2))) {
- /*
- * DARAM/SARAM with odd word alignment
- */
- unsigned long n4;
- unsigned long last_n;
-
- /* dest not aligned -- copy 2 bytes */
- if (((unsigned long)to & 2) && (n >= 2)) {
-#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
- if (__copy_from_user_dsp_2b(to, from))
-#else
- if (copy_from_user_dsp_2b(to, from))
-#endif
- return n;
- to += 2;
- from += 2;
- n -= 2;
- }
- /* middle 4*n bytes */
- last_n = n & 2;
- n4 = n - last_n;
- if ((n = __copy_from_user(to, from, n4)) != 0)
- return n + last_n;
- /* last 2 bytes */
- if (last_n) {
- to += n4;
- from += n4;
-#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
- if (__copy_from_user_dsp_2b(to, from))
-#else
- if (copy_from_user_dsp_2b(to, from))
-#endif
- return 2;
- n = 0;
- }
- } else {
- /*
- * DARAM/SARAM with 4-byte alignment or
- * external memory
- */
- n = __copy_from_user(to, from, n);
- }
- }
- else /* security hole - plug it */
- memzero(to, n);
- return n;
-}
-
-#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
-static inline unsigned long copy_to_user_dsp_2b(void *to, const void *from)
-{
- /* expecting compiler to generate "strh" instruction */
- unsigned short tmp = *(unsigned short *)from;
-
- return __copy_to_user(to, &tmp, 2);
-}
-#endif
-
-/*
- * @n must be multiple of 2
- */
-static inline unsigned long copy_to_user_dsp(void *to, const void *from,
- unsigned long n)
-{
- if (access_ok(VERIFY_WRITE, to, n)) {
- if ((is_dsp_internal_mem(from)) &&
- (((unsigned long)to & 2) || (n & 2))) {
- /*
- * DARAM/SARAM with odd word alignment
- */
- unsigned long n4;
- unsigned long last_n;
-
- /* dest not aligned -- copy 2 bytes */
- if (((unsigned long)to & 2) && (n >= 2)) {
-#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
- if (__copy_to_user_dsp_2b(to, from))
-#else
- if (copy_to_user_dsp_2b(to, from))
-#endif
- return n;
- to += 2;
- from += 2;
- n -= 2;
- }
- /* middle 4*n bytes */
- last_n = n & 2;
- n4 = n - last_n;
- if ((n = __copy_to_user(to, from, n4)) != 0)
- return n + last_n;
- /* last 2 bytes */
- if (last_n) {
- to += n4;
- from += n4;
-#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
- if (__copy_to_user_dsp_2b(to, from))
-#else
- if (copy_to_user_dsp_2b(to, from))
-#endif
- return 2;
- n = 0;
- }
- } else {
- /*
- * DARAM/SARAM with 4-byte alignment or
- * external memory
- */
- n = __copy_to_user(to, from, n);
- }
- }
- return n;
-}
-
-#endif /* _OMAP_DSP_UACCESS_DSP_H */
diff --git a/drivers/Makefile b/drivers/Makefile
index 94b4442..b10394e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/ cbus/
obj-$(CONFIG_I2C) += i2c/
obj-y += cbus/
+obj-y += dsp/dspgateway/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-y += macintosh/
diff --git a/drivers/dsp/dspgateway/Kconfig b/drivers/dsp/dspgateway/Kconfig
new file mode 100644
index 0000000..122164a
--- /dev/null
+++ b/drivers/dsp/dspgateway/Kconfig
@@ -0,0 +1,24 @@
+
+config OMAP_DSP
+ tristate "OMAP DSP driver (DSP Gateway)"
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX
+ select OMAP_MMU_FWK
+ select OMAP_MBOX_FWK
+ help
+ This enables OMAP DSP driver, DSP Gateway.
+
+config OMAP_DSP_MBCMD_VERBOSE
+ bool "Mailbox Command Verbose LOG"
+ depends on OMAP_DSP
+ help
+ This enables kernel log output in the Mailbox command exchanges
+ in the DSP Gateway driver.
+
+config OMAP_DSP_FBEXPORT
+ bool "Framebuffer export to DSP"
+ depends on OMAP_DSP && FB
+ help
+ This enables to map the frame buffer to DSP.
+ By doing this, DSP can access the frame buffer directly without
+ bothering ARM.
+
diff --git a/drivers/dsp/dspgateway/Makefile b/drivers/dsp/dspgateway/Makefile
new file mode 100644
index 0000000..c7d86f3
--- /dev/null
+++ b/drivers/dsp/dspgateway/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the OMAP DSP driver.
+#
+
+# The target object and module list name.
+
+obj-y := dsp_common.o
+
+obj-$(CONFIG_OMAP_DSP) += dsp.o
+
+# Declare multi-part drivers
+
+dsp-objs := dsp_core.o ipbuf.o mblog.o task.o \
+ dsp_ctl_core.o dsp_ctl.o taskwatch.o error.o dsp_mem.o \
+ uaccess_dsp.o
diff --git a/drivers/dsp/dspgateway/dsp.h b/drivers/dsp/dspgateway/dsp.h
new file mode 100644
index 0000000..23321be
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp.h
@@ -0,0 +1,391 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_DSP_H
+#define __PLAT_OMAP_DSP_DSP_H
+
+#include "hardware_dsp.h"
+#include <asm/arch/dsp_common.h>
+#include <asm/arch/mmu.h>
+
+
+#ifdef CONFIG_ARCH_OMAP2
+#include "../../../arch/arm/mach-omap2/prm.h"
+#include "../../../arch/arm/mach-omap2/prm_regbits_24xx.h"
+#include "../../../arch/arm/mach-omap2/cm.h"
+#include "../../../arch/arm/mach-omap2/cm_regbits_24xx.h"
+#endif
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR 96
+#define OMAP_DSP_TASK_MAJOR 97
+
+#define OLD_BINARY_SUPPORT y
+
+#ifdef OLD_BINARY_SUPPORT
+#define MBREV_3_0 0x0017
+#define MBREV_3_2 0x0018
+#endif
+
+#define DSP_INIT_PAGE 0xfff000
+
+#ifdef CONFIG_ARCH_OMAP1
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE 0xfffe00
+#define IDLEPG_SIZE 0x100
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/* 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,
+};
+
+
+typedef int __bitwise arm_dsp_dir_t;
+#define DIR_A2D ((__force arm_dsp_dir_t) 1)
+#define DIR_D2A ((__force arm_dsp_dir_t) 2)
+
+enum cfgstat_e {
+ CFGSTAT_CLEAN = 0,
+ CFGSTAT_READY,
+ CFGSTAT_SUSPEND,
+ CFGSTAT_RESUME, /* request only */
+ CFGSTAT_MAX
+};
+
+enum errcode_e {
+ ERRCODE_WDT = 0,
+ ERRCODE_MMU,
+ ERRCODE_MAX
+};
+
+/* keep 2 entries for TID_FREE and TID_ANON */
+#define TASKDEV_MAX 254
+
+#define MK32(uw,lw) (((u32)(uw)) << 16 | (lw))
+#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
+
+struct sync_seq {
+ u16 da_dsp;
+ u16 da_arm;
+ u16 ad_dsp;
+ u16 ad_arm;
+};
+
+struct mem_sync_struct {
+ struct sync_seq *DARAM;
+ struct sync_seq *SARAM;
+ struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and union mbcmd_hw must be compatible */
+struct mbcmd {
+ u32 data:16;
+ u32 cmd_l:8;
+ u32 cmd_h:7;
+ u32 seq:1;
+};
+
+#define MBCMD_INIT(h, l, d) { \
+ .cmd_h = (h), \
+ .cmd_l = (l), \
+ .data = (d), \
+ }
+
+struct mb_exarg {
+ u8 tid;
+ int argc;
+ u16 *argv;
+};
+
+typedef u32 dsp_long_t; /* must have ability to carry TADD_ABORTADR */
+
+extern void dsp_mbox_start(void);
+extern void dsp_mbox_stop(void);
+extern int dsp_mbox_config(void *p);
+extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
+extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag);
+#define dsp_mbcmd_send(mb) __dsp_mbcmd_send_exarg((mb), NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send_exarg((mb), (arg), 0)
+extern int dsp_mbcmd_send_and_wait_exarg(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_exarg((mb), NULL, (q))
+
+static inline int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
+ struct mb_exarg *arg,
+ int recovery_flag)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
+}
+#define mbcompose_send(cmd_h, cmd_l, data) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
+#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
+#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
+ __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
+
+static inline int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
+ u16 data,
+ struct mb_exarg *arg,
+ wait_queue_head_t *q)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
+}
+#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
+ __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+ NULL, (q))
+#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
+ __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+ (arg), (q))
+
+extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(u16 ln, u16 lsz, void *base);
+extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
+extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
+extern struct ipbuf_head *get_free_ipbuf(u8 tid);
+extern void release_ipbuf(struct ipbuf_head *ipb_h);
+extern void balance_ipbuf(void);
+extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
+extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+ do { \
+ (ipbuf_pvt)->s = TID_FREE; \
+ } while(0)
+
+extern int mbox_revision;
+
+extern int dsp_cfgstat_request(enum cfgstat_e st);
+extern enum cfgstat_e dsp_cfgstat_get_stat(void);
+extern int dsp_set_runlevel(u8 level);
+
+extern int dsp_task_config_all(u8 n);
+extern void dsp_task_unconfig_all(void);
+extern u8 dsp_task_count(void);
+extern int dsp_taskmod_busy(void);
+extern int dsp_mkdev(char *name);
+extern int dsp_rmdev(char *name);
+extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
+extern int dsp_tdel_minor(unsigned char minor);
+extern int dsp_tkill_minor(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(u8 tid, u16 bid);
+
+extern int 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, ...);
+#ifdef CONFIG_ARCH_OMAP1
+extern void dsp_mem_usecount_clear(void);
+#endif
+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);
+extern void dsp_twch_touch(void);
+
+extern void dsp_err_start(void);
+extern void dsp_err_stop(void);
+extern void dsp_err_set(enum errcode_e code, unsigned long arg);
+extern void dsp_err_clear(enum errcode_e code);
+extern int dsp_err_isset(enum errcode_e code);
+
+enum cmd_l_type_e {
+ CMD_L_TYPE_NULL,
+ CMD_L_TYPE_TID,
+ CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+ char *name;
+ enum cmd_l_type_e cmd_l_type;
+ void (*handler)(struct mbcmd *mb);
+};
+
+extern const struct cmdinfo *cmdinfo[];
+
+#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
+extern char *subcmd_name(struct mbcmd *mb);
+
+extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
+
+extern struct omap_mmu dsp_mmu;
+
+#define dsp_mem_enable(addr) omap_mmu_mem_enable(&dsp_mmu, (addr))
+#define dsp_mem_disable(addr) omap_mmu_mem_disable(&dsp_mmu, (addr))
+
+#define DSPSPACE_SIZE 0x1000000
+
+#define omap_set_bit_regw(b,r) \
+ do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regw(b,r) \
+ do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
+#define omap_set_bit_regl(b,r) \
+ do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regl(b,r) \
+ do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
+#define omap_set_bits_regl(val,mask,r) \
+ do { omap_writel((omap_readl(r) & ~(mask)) | (val), (r)); } while(0)
+
+#define dspword_to_virt(dw) ((void *)(dspmem_base + ((dw) << 1)))
+#define dspbyte_to_virt(db) ((void *)(dspmem_base + (db)))
+#define virt_to_dspword(va) \
+ ((dsp_long_t)(((unsigned long)(va) - dspmem_base) >> 1))
+#define virt_to_dspbyte(va) \
+ ((dsp_long_t)((unsigned long)(va) - dspmem_base))
+#define is_dsp_internal_mem(va) \
+ (((unsigned long)(va) >= dspmem_base) && \
+ ((unsigned long)(va) < dspmem_base + dspmem_size))
+#define is_dspbyte_internal_mem(db) ((db) < dspmem_size)
+#define is_dspword_internal_mem(dw) (((dw) << 1) < dspmem_size)
+
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * MPUI byteswap/wordswap on/off
+ * default setting: wordswap = all, byteswap = APIMEM only
+ */
+#define mpui_wordswap_on() \
+ omap_set_bits_regl(MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL_WORDSWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_wordswap_off() \
+ omap_set_bits_regl(MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL_WORDSWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_byteswap_on() \
+ omap_set_bits_regl(MPUI_CTRL_BYTESWAP_API, MPUI_CTRL_BYTESWAP_MASK, \
+ MPUI_CTRL)
+
+#define mpui_byteswap_off() \
+ omap_set_bits_regl(MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL_BYTESWAP_MASK, \
+ 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() omap_clr_bit_regl(TC_ENDIANISM_EN, TC_ENDIANISM)
+
+/*
+ * enable priority registers, EMIF, MPUI control logic
+ */
+#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#define __dsp_disable() omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#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)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP2
+/*
+ * PRCM / IPI control logic
+ *
+ * REVISIT: these macros should probably be static inline functions
+ */
+#define __dsp_core_enable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ & ~OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_core_disable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ | OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_enable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ & ~OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_disable() \
+ do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+ | OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#if defined(CONFIG_ARCH_OMAP1)
+extern struct clk *dsp_ck_handle;
+extern struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct clk *dsp_fck_handle;
+extern struct clk *dsp_ick_handle;
+#endif
+extern dsp_long_t dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+enum cpustat_e {
+ CPUSTAT_RESET = 0,
+#ifdef CONFIG_ARCH_OMAP1
+ CPUSTAT_GBL_IDLE,
+ CPUSTAT_CPU_IDLE,
+#endif
+ CPUSTAT_RUN,
+ CPUSTAT_MAX
+};
+
+int dsp_set_rstvect(dsp_long_t adr);
+dsp_long_t dsp_get_rstvect(void);
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size);
+void dsp_reset_idle_boot_base(void);
+void dsp_cpustat_request(enum cpustat_e req);
+enum cpustat_e dsp_cpustat_get_stat(void);
+u16 dsp_cpustat_get_icrmask(void);
+void dsp_cpustat_set_icrmask(u16 mask);
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define command_dvfs_stop(m) (0)
+#define command_dvfs_start(m) (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define command_dvfs_stop(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_STOP))
+#define command_dvfs_start(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_START))
+#endif
+
+extern struct omap_dsp *omap_dsp;
+
+extern int dsp_late_init(void);
+
+#endif /* __PLAT_OMAP_DSP_DSP_H */
diff --git a/drivers/dsp/dspgateway/dsp_common.c b/drivers/dsp/dspgateway/dsp_common.c
new file mode 100644
index 0000000..99be995
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_common.c
@@ -0,0 +1,627 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/irq.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp.h"
+
+#ifdef CONFIG_ARCH_OMAP1
+#include <asm/arch/tc.h>
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
+#endif
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG)
+#endif
+
+struct omap_dsp *omap_dsp;
+
+#if defined(CONFIG_ARCH_OMAP1)
+struct clk *dsp_ck_handle;
+struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+struct clk *dsp_fck_handle;
+struct clk *dsp_ick_handle;
+#endif
+dsp_long_t dspmem_base, dspmem_size,
+ daram_base, daram_size,
+ saram_base, saram_size;
+
+static struct cpustat {
+ struct mutex lock;
+ enum cpustat_e stat;
+ enum cpustat_e req;
+ u16 icrmask;
+#ifdef CONFIG_ARCH_OMAP1
+ struct {
+ int mpui;
+ int mem;
+ int mem_delayed;
+ } usecount;
+ int (*mem_req_cb)(void);
+ void (*mem_rel_cb)(void);
+#endif
+} cpustat = {
+ .stat = CPUSTAT_RESET,
+ .icrmask = 0xffff,
+};
+
+int dsp_set_rstvect(dsp_long_t adr)
+{
+ unsigned long *dst_adr;
+
+ if (adr >= DSPSPACE_SIZE)
+ return -EINVAL;
+
+ dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+ /* word swap */
+ *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
+ /* fill 8 bytes! */
+ *(dst_adr + 1) = 0;
+ /* direct boot */
+ dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
+
+ return 0;
+}
+
+dsp_long_t dsp_get_rstvect(void)
+{
+ unsigned long *dst_adr;
+
+ dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+ return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
+{
+ int i;
+ u16 *src = (u16 *)src_c;
+ int len_w;
+
+ /* len must be multiple of 2. */
+ if (len & 1)
+ BUG();
+
+ len_w = len / 2;
+ for (i = 0; i < len_w; i++) {
+ /* byte swap copy */
+ *dst = ((*src & 0x00ff) << 8) |
+ ((*src & 0xff00) >> 8);
+ src++;
+ dst++;
+ }
+}
+
+/* program size must be multiple of 2 */
+#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 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 */ \
+ 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 /* 0x20: nop */ \
+}
+
+/*
+ * idle_boot base:
+ * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
+ * This value is used before DSP Gateway driver is initialized.
+ * DSP Gateway driver will overwrite this value with other value,
+ * to avoid confliction with the user program.
+ */
+static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI;
+
+static void dsp_gbl_idle(void)
+{
+ unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
+
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+
+#if 0
+ dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
+#endif
+ simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+ GBL_IDLE_TEXT_SIZE);
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+ else
+ dsp_set_rstvect(idle_boot_base);
+
+ __dsp_run();
+ udelay(100); /* to make things stable */
+ clk_disable(api_ck_handle);
+}
+
+static void dsp_cpu_idle(void)
+{
+ u16 icr_tmp;
+ unsigned char icrh, icrl;
+
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+
+ /*
+ * icr settings:
+ * DMA should not sleep for DARAM/SARAM access
+ * DPLL should not sleep while any other domain is active
+ */
+ icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL);
+ icrh = icr_tmp >> 8;
+ icrl = icr_tmp & 0xff;
+ {
+ 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),
+ CPU_IDLE_TEXT_SIZE);
+ }
+ if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+ dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+ else
+ dsp_set_rstvect(idle_boot_base);
+ __dsp_run();
+ udelay(100); /* to make things stable */
+ clk_disable(api_ck_handle);
+}
+
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size)
+{
+ if (adr == idle_boot_base)
+ return;
+ idle_boot_base = adr;
+ if ((size < GBL_IDLE_TEXT_SIZE) ||
+ (size < CPU_IDLE_TEXT_SIZE)) {
+ printk(KERN_ERR
+ "omapdsp: size for idle program is not enough!\n");
+ BUG();
+ }
+
+ /* 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();
+}
+
+void dsp_reset_idle_boot_base(void)
+{
+ idle_boot_base = DSP_BOOT_ADR_MPUI;
+}
+#else
+void dsp_reset_idle_boot_base(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static int init_done;
+
+static int omap_dsp_init(void)
+{
+ mutex_init(&cpustat.lock);
+
+ dspmem_size = 0;
+#ifdef CONFIG_ARCH_OMAP15XX
+ if (cpu_is_omap15xx()) {
+ 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
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx()) {
+ dspmem_base = DSP_MEM_24XX_VIRT;
+ dspmem_size = DSP_MEM_24XX_SIZE;
+ daram_base = OMAP24XX_DARAM_BASE;
+ daram_size = OMAP24XX_DARAM_SIZE;
+ saram_base = OMAP24XX_SARAM_BASE;
+ saram_size = OMAP24XX_SARAM_SIZE;
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+ /* To be Revisited for 3430 */
+ if (cpu_is_omap34xx()) {
+ return -ENODEV;
+ }
+#endif
+ if (dspmem_size == 0) {
+ printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_ARCH_OMAP1)
+ dsp_ck_handle = clk_get(NULL, "dsp_ck");
+ if (IS_ERR(dsp_ck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
+ return PTR_ERR(dsp_ck_handle);
+ }
+
+ api_ck_handle = clk_get(NULL, "api_ck");
+ if (IS_ERR(api_ck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
+ if (dsp_ck_handle != NULL)
+ clk_put(dsp_ck_handle);
+ return PTR_ERR(api_ck_handle);
+ }
+
+ /* This is needed for McBSP init, released in late_initcall */
+ clk_enable(api_ck_handle);
+
+ __dsp_enable();
+ mpui_byteswap_off();
+ mpui_wordswap_on();
+ tc_wordswap();
+#elif defined(CONFIG_ARCH_OMAP2)
+ dsp_fck_handle = clk_get(NULL, "dsp_fck");
+ if (IS_ERR(dsp_fck_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
+ return PTR_ERR(dsp_fck_handle);
+ }
+
+ dsp_ick_handle = clk_get(NULL, "dsp_ick");
+ if (IS_ERR(dsp_ick_handle)) {
+ printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
+ if (dsp_fck_handle != NULL)
+ clk_put(dsp_fck_handle);
+ return PTR_ERR(dsp_ick_handle);
+ }
+#endif
+
+ init_done = 1;
+ pr_info("omap_dsp_init() done\n");
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static int __dsp_late_init(void)
+{
+ clk_disable(api_ck_handle);
+ return 0;
+}
+late_initcall(__dsp_late_init);
+#endif
+
+static void dsp_cpustat_update(void)
+{
+ if (!init_done)
+ omap_dsp_init();
+
+ if (cpustat.req == CPUSTAT_RUN) {
+ if (cpustat.stat < CPUSTAT_RUN) {
+#if defined(CONFIG_ARCH_OMAP1)
+ __dsp_reset();
+ clk_enable(api_ck_handle);
+ udelay(10);
+ __dsp_run();
+#elif defined(CONFIG_ARCH_OMAP2)
+ __dsp_core_disable();
+ udelay(10);
+ __dsp_core_enable();
+#endif
+ cpustat.stat = CPUSTAT_RUN;
+ }
+ return;
+ }
+
+ /* cpustat.req < CPUSTAT_RUN */
+
+ if (cpustat.stat == CPUSTAT_RUN) {
+#ifdef CONFIG_ARCH_OMAP1
+ clk_disable(api_ck_handle);
+#endif
+ }
+
+#ifdef CONFIG_ARCH_OMAP1
+ /*
+ * (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;
+ }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+ /*
+ * no user, no request
+ */
+ if (cpustat.stat != CPUSTAT_RESET) {
+#if defined(CONFIG_ARCH_OMAP1)
+ __dsp_reset();
+#elif defined(CONFIG_ARCH_OMAP2)
+ __dsp_core_disable();
+#endif
+ cpustat.stat = CPUSTAT_RESET;
+ }
+}
+
+void dsp_cpustat_request(enum cpustat_e req)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.req = req;
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+enum cpustat_e dsp_cpustat_get_stat(void)
+{
+ return cpustat.stat;
+}
+
+u16 dsp_cpustat_get_icrmask(void)
+{
+ return cpustat.icrmask;
+}
+
+void dsp_cpustat_set_icrmask(u16 mask)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.icrmask = mask;
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+void omap_dsp_request_mpui(void)
+{
+ mutex_lock(&cpustat.lock);
+ if (cpustat.usecount.mpui++ == 0)
+ dsp_cpustat_update();
+ mutex_unlock(&cpustat.lock);
+}
+
+void omap_dsp_release_mpui(void)
+{
+ mutex_lock(&cpustat.lock);
+ 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();
+ mutex_unlock(&cpustat.lock);
+}
+
+int omap_dsp_request_mem(void)
+{
+ int ret = 0;
+
+ mutex_lock(&cpustat.lock);
+ 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:
+ mutex_unlock(&cpustat.lock);
+
+ return ret;
+}
+
+/*
+ * release_mem will be delayed.
+ */
+static void do_release_mem(struct work_struct *dummy)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.usecount.mem_delayed = 0;
+ if (cpustat.usecount.mem == 0) {
+ dsp_cpustat_update();
+ if (cpustat.mem_rel_cb)
+ cpustat.mem_rel_cb();
+ }
+ mutex_unlock(&cpustat.lock);
+}
+
+static DECLARE_DELAYED_WORK(mem_rel_work, do_release_mem);
+
+int omap_dsp_release_mem(void)
+{
+ mutex_lock(&cpustat.lock);
+
+ /* 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);
+ }
+
+ mutex_unlock(&cpustat.lock);
+
+ return 0;
+}
+
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
+{
+ mutex_lock(&cpustat.lock);
+
+ 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);
+
+ mutex_unlock(&cpustat.lock);
+}
+
+void dsp_unregister_mem_cb(void)
+{
+ mutex_lock(&cpustat.lock);
+ cpustat.mem_req_cb = NULL;
+ cpustat.mem_rel_cb = NULL;
+ mutex_unlock(&cpustat.lock);
+}
+#else
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { }
+void dsp_unregister_mem_cb(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+arch_initcall(omap_dsp_init);
+
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(omap_dsp_request_mpui);
+EXPORT_SYMBOL(omap_dsp_release_mpui);
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_OMAP_DSP_MODULE
+#if defined(CONFIG_ARCH_OMAP1)
+EXPORT_SYMBOL(dsp_ck_handle);
+EXPORT_SYMBOL(api_ck_handle);
+#elif defined(CONFIG_ARCH_OMAP2)
+EXPORT_SYMBOL(dsp_fck_handle);
+EXPORT_SYMBOL(dsp_ick_handle);
+#endif
+EXPORT_SYMBOL(omap_dsp);
+EXPORT_SYMBOL(dspmem_base);
+EXPORT_SYMBOL(dspmem_size);
+EXPORT_SYMBOL(daram_base);
+EXPORT_SYMBOL(daram_size);
+EXPORT_SYMBOL(saram_base);
+EXPORT_SYMBOL(saram_size);
+EXPORT_SYMBOL(dsp_set_rstvect);
+EXPORT_SYMBOL(dsp_get_rstvect);
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(dsp_set_idle_boot_base);
+EXPORT_SYMBOL(dsp_reset_idle_boot_base);
+#endif /* CONFIG_ARCH_OMAP1 */
+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);
+EXPORT_SYMBOL(cpu_architecture);
+EXPORT_SYMBOL(pmd_clear_bad);
+#endif
diff --git a/drivers/dsp/dspgateway/dsp_core.c b/drivers/dsp/dspgateway/dsp_core.c
new file mode 100644
index 0000000..05274be
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_core.c
@@ -0,0 +1,663 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+static struct sync_seq *mbseq;
+static u16 mbseq_expect_tmp;
+static u16 *mbseq_expect = &mbseq_expect_tmp;
+
+extern int dsp_mem_late_init(void);
+
+/*
+ * mailbox commands
+ */
+extern void mbox_wdsnd(struct mbcmd *mb);
+extern void mbox_wdreq(struct mbcmd *mb);
+extern void mbox_bksnd(struct mbcmd *mb);
+extern void mbox_bkreq(struct mbcmd *mb);
+extern void mbox_bkyld(struct mbcmd *mb);
+extern void mbox_bksndp(struct mbcmd *mb);
+extern void mbox_bkreqp(struct mbcmd *mb);
+extern void mbox_tctl(struct mbcmd *mb);
+extern void mbox_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbox_wdt(struct mbcmd *mb);
+#endif
+extern void mbox_suspend(struct mbcmd *mb);
+static void mbox_kfunc(struct mbcmd *mb);
+extern void mbox_tcfg(struct mbcmd *mb);
+extern void mbox_tadd(struct mbcmd *mb);
+extern void mbox_tdel(struct mbcmd *mb);
+extern void mbox_dspcfg(struct mbcmd *mb);
+extern void mbox_regrw(struct mbcmd *mb);
+extern void mbox_getvar(struct mbcmd *mb);
+extern void mbox_err(struct mbcmd *mb);
+extern void mbox_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+ cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbox_wdsnd },
+ cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbox_wdreq },
+ cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbox_bksnd },
+ cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbox_bkreq },
+ cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbox_bkyld },
+ cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbox_bksndp },
+ cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbox_bkreqp },
+ cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbox_tctl },
+ cif_poll = { "POLL", CMD_L_TYPE_NULL, mbox_poll },
+#ifdef OLD_BINARY_SUPPORT
+ /* v3.3 obsolete */
+ cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbox_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, mbox_suspend },
+ cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbox_kfunc },
+ cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbox_tcfg },
+ cif_tadd = { "TADD", CMD_L_TYPE_TID, mbox_tadd },
+ cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbox_tdel },
+ cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL },
+ cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbox_dspcfg },
+ cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbox_regrw },
+ cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbox_getvar },
+ cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL },
+ cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbox_err },
+ cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbox_dbg };
+
+#define MBOX_CMD_MAX 0x80
+const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
+ [MBOX_CMD_DSP_WDSND] = &cif_wdsnd,
+ [MBOX_CMD_DSP_WDREQ] = &cif_wdreq,
+ [MBOX_CMD_DSP_BKSND] = &cif_bksnd,
+ [MBOX_CMD_DSP_BKREQ] = &cif_bkreq,
+ [MBOX_CMD_DSP_BKYLD] = &cif_bkyld,
+ [MBOX_CMD_DSP_BKSNDP] = &cif_bksndp,
+ [MBOX_CMD_DSP_BKREQP] = &cif_bkreqp,
+ [MBOX_CMD_DSP_TCTL] = &cif_tctl,
+ [MBOX_CMD_DSP_POLL] = &cif_poll,
+#ifdef OLD_BINARY_SUPPORT
+ [MBOX_CMD_DSP_WDT] = &cif_wdt, /* v3.3 obsolete */
+#endif
+ [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
+ [MBOX_CMD_DSP_PM] = &cif_pm,
+ [MBOX_CMD_DSP_SUSPEND] = &cif_suspend,
+ [MBOX_CMD_DSP_KFUNC] = &cif_kfunc,
+ [MBOX_CMD_DSP_TCFG] = &cif_tcfg,
+ [MBOX_CMD_DSP_TADD] = &cif_tadd,
+ [MBOX_CMD_DSP_TDEL] = &cif_tdel,
+ [MBOX_CMD_DSP_TSTOP] = &cif_tstop,
+ [MBOX_CMD_DSP_DSPCFG] = &cif_dspcfg,
+ [MBOX_CMD_DSP_REGRW] = &cif_regrw,
+ [MBOX_CMD_DSP_GETVAR] = &cif_getvar,
+ [MBOX_CMD_DSP_SETVAR] = &cif_setvar,
+ [MBOX_CMD_DSP_ERR] = &cif_err,
+ [MBOX_CMD_DSP_DBG] = &cif_dbg,
+};
+
+#define list_for_each_entry_safe_natural(p,n,h,m) \
+ list_for_each_entry_safe(p,n,h,m)
+#define __BUILD_KFUNC(fn, dir) \
+static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
+{ \
+ struct dsp_kfunc_device *p, *tmp; \
+ int ret, fail = 0; \
+ \
+ list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) { \
+ if (type && (p->type != type)) \
+ continue; \
+ if (p->fn == NULL) \
+ continue; \
+ ret = p->fn(p, stage); \
+ if (ret) { \
+ printk(KERN_ERR "%s %s failed\n", #fn, p->name); \
+ fail++; \
+ } \
+ } \
+ return fail; \
+}
+#define BUILD_KFUNC(fn, dir) \
+__BUILD_KFUNC(fn, dir) \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp) \
+{ \
+ return __dsp_kfunc_##fn##_devices(dsp, 0, 0); \
+}
+#define BUILD_KFUNC_CTL(fn, dir) \
+__BUILD_KFUNC(fn, dir) \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage) \
+{ \
+ return __dsp_kfunc_##fn##_devices(dsp, type, stage); \
+}
+
+BUILD_KFUNC(probe, natural)
+BUILD_KFUNC(remove, reverse)
+BUILD_KFUNC_CTL(enable, natural)
+BUILD_KFUNC_CTL(disable, reverse)
+
+int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
+{
+ int try;
+
+ if (*(volatile u16 *)adr == val)
+ return 0;
+
+ for (try = 0; try < try_cnt; try++) {
+ udelay(1);
+ if (*(volatile u16 *)adr == val) {
+ /* success! */
+ pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
+ return 0;
+ }
+ }
+
+ /* fail! */
+ return -1;
+}
+
+static int mbcmd_sender_prepare(void *data)
+{
+ struct mb_exarg *arg = data;
+ int i, ret = 0;
+ /*
+ * 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, TID_FREE, 10) < 0) {
+ printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ for (i = 0; i < arg->argc; i++) {
+ ipbuf_sys_ad->d[i] = arg->argv[i];
+ }
+ ipbuf_sys_ad->s = arg->tid;
+ out:
+ dsp_mem_disable(ipbuf_sys_ad);
+ return ret;
+}
+
+/*
+ * __dsp_mbcmd_send_exarg(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ int recovery_flag)
+{
+ int ret = 0;
+
+ if (unlikely(omap_dsp->enabled == 0)) {
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 1;
+ }
+
+ /*
+ * while MMU fault is set,
+ * only recovery command can be executed
+ */
+ if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
+ printk(KERN_ERR
+ "mbox: mmu interrupt is set. %s is aborting.\n",
+ cmd_name(*mb));
+ goto out;
+ }
+
+ ret = omap_mbox_msg_send(omap_dsp->mbox,
+ *(mbox_msg_t *)mb, (void*)arg);
+ if (ret)
+ goto out;
+
+ if (mbseq)
+ mbseq->ad_arm++;
+
+ mblog_add(mb, DIR_A2D);
+ out:
+ return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+ wait_queue_head_t *q)
+{
+ int ret;
+
+ DEFINE_WAIT(wait);
+ prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+ ret = dsp_mbcmd_send_exarg(mb, arg);
+ if (ret < 0)
+ goto out;
+ schedule_timeout(DSP_TIMEOUT);
+ out:
+ finish_wait(q, &wait);
+ return ret;
+}
+
+/*
+ * mbcmd receiver
+ */
+static int mbcmd_receiver(void* msg)
+{
+ struct mbcmd *mb = (struct mbcmd *)&msg;
+
+ if (cmdinfo[mb->cmd_h] == NULL) {
+ printk(KERN_ERR
+ "invalid message (%08x) for mbcmd_receiver().\n",
+ (mbox_msg_t)msg);
+ return -1;
+ }
+
+ (*mbseq_expect)++;
+
+ mblog_add(mb, DIR_D2A);
+
+ /* call handler for the command */
+ if (cmdinfo[mb->cmd_h]->handler)
+ cmdinfo[mb->cmd_h]->handler(mb);
+ else
+ printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
+ cmd_name(*mb));
+ return 0;
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mbox_start(void)
+{
+ omap_mbox_init_seq(omap_dsp->mbox);
+ mbseq_expect_tmp = 0;
+}
+
+void dsp_mbox_stop(void)
+{
+ mbseq = NULL;
+ mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mbox_config(void *p)
+{
+ 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;
+}
+
+static int __init dsp_mbox_init(void)
+{
+ omap_dsp->mbox = omap_mbox_get("dsp");
+ if (IS_ERR(omap_dsp->mbox)) {
+ printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+ return -ENODEV;
+ }
+
+ omap_dsp->mbox->rxq->callback = mbcmd_receiver;
+ omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
+
+ return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+ omap_dsp->mbox->txq->callback = NULL;
+ omap_dsp->mbox->rxq->callback = NULL;
+
+ omap_mbox_put(omap_dsp->mbox);
+
+ if (mbsync_hold_mem_active) {
+ dsp_mem_disable((void *)daram_base);
+ mbsync_hold_mem_active = 0;
+ }
+}
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbox_fbctl_upd(void);
+extern void mbox_fbctl_disable(struct mbcmd *mb);
+
+static void mbox_kfunc_fbctl(struct mbcmd *mb)
+{
+ switch (mb->data) {
+ case FBCTL_UPD:
+ mbox_fbctl_upd();
+ break;
+ case FBCTL_DISABLE:
+ mbox_fbctl_disable(mb);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
+ }
+}
+
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
+{
+ int ret = -1;
+
+ switch (data) {
+ case DVFS_START: /* ACK from DSP */
+ /* TBD */
+ break;
+ case AUDIO_PWR_UP:
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+ if (ret == 0)
+ ret++;
+ break;
+ case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 1);
+ break;
+ case AUDIO_PWR_DOWN2:
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+ break;
+ case DSP_PWR_DOWN:
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 0;
+ break;
+ default:
+ printk(KERN_ERR
+ "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+ break;
+ }
+
+ if (unlikely(ret < 0)) {
+ printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+ return;
+ }
+
+ if (likely(ret == 0))
+ return;
+
+ mbcompose_send(KFUNC, KFUNC_POWER, data);
+}
+
+static void mbox_kfunc(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case KFUNC_FBCTL:
+ mbox_kfunc_fbctl(mb);
+ break;
+ case KFUNC_POWER:
+ mbox_kfunc_power(mb->data);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
+ }
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static inline void dsp_clk_enable(void) {}
+static inline void dsp_clk_disable(void) {}
+#elif defined(CONFIG_ARCH_OMAP2)
+static inline void dsp_clk_enable(void)
+{
+ u32 r;
+
+ /*XXX should be handled in mach-omap[1,2] XXX*/
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (1 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+
+ r = cm_read_mod_reg(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+ r |= OMAP2420_AUTO_DSP_IPI;
+ cm_write_mod_reg(r, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+ r = cm_read_mod_reg(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+ r |= OMAP24XX_AUTOSTATE_DSP;
+ cm_write_mod_reg(r, OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+
+ clk_enable(dsp_fck_handle);
+ clk_enable(dsp_ick_handle);
+ __dsp_per_enable();
+}
+static inline void dsp_clk_disable(void)
+{
+ __dsp_per_disable();
+ clk_disable(dsp_ick_handle);
+ clk_disable(dsp_fck_handle);
+
+ prm_write_mod_reg(OMAP24XX_FORCESTATE | (3 << OMAP_POWERSTATE_SHIFT),
+ OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+}
+#endif
+
+int dsp_late_init(void)
+{
+ int ret;
+
+ dsp_clk_enable();
+ ret = dsp_mem_late_init();
+ if (ret)
+ return ret;
+ ret = dsp_mbox_init();
+ if (ret)
+ goto fail_mbox;
+#ifdef CONFIG_ARCH_OMAP1
+ dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+#endif
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret)
+ goto fail_kfunc;
+ omap_dsp->enabled = 1;
+
+ return 0;
+
+ fail_kfunc:
+ dsp_mbox_exit();
+ fail_mbox:
+ dsp_clk_disable();
+
+ return ret;
+}
+
+extern int dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern int dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * driver functions
+ */
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct omap_dsp *info;
+ struct dsp_platform_data *pdata = pdev->dev.platform_data;
+
+ dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
+
+ info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+ if (unlikely(info == NULL)) {
+ dev_dbg(&pdev->dev, "no memory for info\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, info);
+ omap_dsp = info;
+
+ mutex_init(&info->lock);
+ info->dev = &pdev->dev;
+ info->kdev_list = &pdata->kdev_list;
+
+ ret = dsp_kfunc_probe_devices(info);
+ if (ret) {
+ ret = -ENXIO;
+ goto fail_kfunc;
+ }
+
+ ret = dsp_ctl_core_init();
+ if (ret)
+ goto fail_ctl_core;
+ ret = dsp_mem_init();
+ if (ret)
+ goto fail_mem;
+ ret = dsp_ctl_init();
+ if (unlikely(ret))
+ goto fail_ctl_init;
+ mblog_init();
+ ret = dsp_taskmod_init();
+ if (ret)
+ goto fail_taskmod;
+
+ return 0;
+
+ fail_taskmod:
+ mblog_exit();
+ dsp_ctl_exit();
+ fail_ctl_init:
+ dsp_mem_exit();
+ fail_mem:
+ dsp_ctl_core_exit();
+ fail_ctl_core:
+ dsp_kfunc_remove_devices(info);
+ fail_kfunc:
+ kfree(info);
+
+ return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+ struct omap_dsp *info = platform_get_drvdata(pdev);
+
+ dsp_cpustat_request(CPUSTAT_RESET);
+
+ dsp_cfgstat_request(CFGSTAT_CLEAN);
+ dsp_mbox_exit();
+ dsp_taskmod_exit();
+ mblog_exit();
+ dsp_ctl_exit();
+ dsp_mem_exit();
+
+ dsp_ctl_core_exit();
+
+#ifdef CONFIG_ARCH_OMAP2
+ __dsp_per_disable();
+ clk_disable(dsp_ick_handle);
+ clk_disable(dsp_fck_handle);
+#endif
+ dsp_kfunc_remove_devices(info);
+ kfree(info);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dsp_cfgstat_request(CFGSTAT_SUSPEND);
+
+ return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+ dsp_cfgstat_request(CFGSTAT_RESUME);
+
+ return 0;
+}
+#else
+#define dsp_drv_suspend NULL
+#define dsp_drv_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dsp_driver = {
+ .probe = dsp_drv_probe,
+ .remove = dsp_drv_remove,
+ .suspend = dsp_drv_suspend,
+ .resume = dsp_drv_resume,
+ .driver = {
+ .name = "dsp",
+ },
+};
+
+static int __init omap_dsp_mod_init(void)
+{
+ return platform_driver_register(&dsp_driver);
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+ platform_driver_unregister(&dsp_driver);
+}
+
+/* module dependency: need mailbox module that have mbox_dsp_info */
+extern struct omap_mbox mbox_dsp_info;
+struct omap_mbox *mbox_dep = &mbox_dsp_info;
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
diff --git a/drivers/dsp/dspgateway/dsp_ctl.c b/drivers/dsp/dspgateway/dsp_ctl.c
new file mode 100644
index 0000000..79c1fdf
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_ctl.c
@@ -0,0 +1,1069 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+enum dsp_space_e {
+ SPACE_MEM,
+ SPACE_IO,
+};
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static enum fbstat_e {
+ FBSTAT_DISABLED = 0,
+ FBSTAT_ENABLED,
+ FBSTAT_MAX,
+} fbstat = FBSTAT_ENABLED;
+#endif
+
+static enum cfgstat_e cfgstat;
+int mbox_revision;
+static u8 n_stask;
+
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+
+#define __ATTR_RW(_name, _mode) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
+static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
+static struct device_attribute dev_attr_icrmask = __ATTR_RW(icrmask, 0644);
+static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
+
+/*
+ * misc interactive mailbox command operations
+ */
+static struct misc_mb_wait_struct {
+ struct mutex lock;
+ wait_queue_head_t wait_q;
+ u8 cmd_h;
+ u8 cmd_l;
+ u16 *retvp;
+} misc_mb_wait = {
+ .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
+ .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
+};
+
+static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
+ u16 *retvp)
+{
+ struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&misc_mb_wait.lock))
+ return -EINTR;
+
+ misc_mb_wait.cmd_h = mb.cmd_h;
+ misc_mb_wait.cmd_l = mb.cmd_l;
+ misc_mb_wait.retvp = retvp;
+ dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
+
+ if (misc_mb_wait.cmd_h != 0)
+ ret = -EINVAL;
+
+ mutex_unlock(&misc_mb_wait.lock);
+ return ret;
+}
+
+#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
+ __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
+ (data), (retvp));
+
+static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
+{
+ volatile u16 *buf;
+ int i;
+
+ /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
+ if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+ (misc_mb_wait.cmd_h != mb->cmd_h) ||
+ (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
+ const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+ char cmdstr[32];
+
+ if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
+ sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
+ else
+ strcpy(cmdstr, ci->name);
+ printk(KERN_WARNING
+ "mbox: unexpected command %s received!\n", cmdstr);
+ return -1;
+ }
+
+ /*
+ * if argc == 1, receive data through mbox:data register.
+ * if argc > 1, receive through ipbuf_sys.
+ */
+ if (argc == 1)
+ misc_mb_wait.retvp[0] = mb->data;
+ else if (argc > 1) {
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
+ cmdinfo[mb->cmd_h]->name);
+ return -1;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+ printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
+ cmdinfo[mb->cmd_h]->name);
+ dsp_mem_disable(ipbuf_sys_da);
+ return -1;
+ }
+ /* need word access. do not use memcpy. */
+ buf = ipbuf_sys_da->d;
+ for (i = 0; i < argc; i++)
+ misc_mb_wait.retvp[i] = buf[i];
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+ }
+
+ misc_mb_wait.cmd_h = 0;
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ return 0;
+}
+
+static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
+{
+ u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: register read error!\n");
+
+ return ret;
+}
+
+static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
+{
+ u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
+ struct mb_exarg arg = {
+ .tid = TID_ANON,
+ .argc = 1,
+ .argv = &val,
+ };
+
+ mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
+ return 0;
+}
+
+static int dsp_getvar(u8 varid, u16 *val)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: variable read error!\n");
+
+ return ret;
+}
+
+static int dsp_setvar(u8 varid, u16 val)
+{
+ mbcompose_send(SETVAR, varid, val);
+ return 0;
+}
+
+/*
+ * dsp_cfg() return value
+ * = 0: OK
+ * = 1: failed, but state is clear. (DSPCFG command failed)
+ * < 0: failed. need cleanup.
+ */
+static int dsp_cfg(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+ /* for safety */
+ dsp_mem_usecount_clear();
+#endif
+
+ /*
+ * DSPCFG command and dsp_mem_start() must be called
+ * while internal mem is on.
+ */
+ dsp_mem_enable((void *)dspmem_base);
+
+ dsp_mbox_start();
+ dsp_twch_start();
+ dsp_mem_start();
+ dsp_err_start();
+
+ mbox_revision = -1;
+
+ ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
+ if (ret < 0) {
+ if (ret != -EINTR)
+ printk(KERN_ERR "omapdsp: configuration error!\n");
+ ret = 1;
+ goto out;
+ }
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
+ /*
+ * MBREV 3.2 or earlier doesn't assume DMA domain is on
+ * when DSPCFG command is sent
+ */
+ if ((mbox_revision == MBREV_3_0) ||
+ (mbox_revision == MBREV_3_2)) {
+ if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
+ goto out;
+ }
+#endif
+
+ if ((ret = dsp_task_config_all(n_stask)) < 0)
+ goto out;
+
+ /* initialization */
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ fbstat = FBSTAT_ENABLED;
+#endif
+
+ /* send parameter */
+ ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
+ if (ret < 0)
+ goto out;
+
+ /* create runtime sysfs entries */
+ ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+ out:
+ dsp_mem_disable((void *)dspmem_base);
+ return ret;
+}
+
+static int dsp_uncfg(void)
+{
+ if (dsp_taskmod_busy()) {
+ printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+ return -EBUSY;
+ }
+
+ /* FIXME: lock task module */
+
+ /* remove runtime sysfs entries */
+ device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
+
+ dsp_mbox_stop();
+ dsp_twch_stop();
+ dsp_mem_stop();
+ dsp_err_stop();
+ dsp_dbg_stop();
+ dsp_task_unconfig_all();
+ ipbuf_stop();
+
+ return 0;
+}
+
+static int dsp_suspend(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
+ if (ret < 0) {
+ if (ret != -EINVAL)
+ printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+ return ret;
+ }
+
+ udelay(100); /* wait for DSP-side execution */
+ return 0;
+}
+
+int dsp_cfgstat_request(enum cfgstat_e st_req)
+{
+ static DEFINE_MUTEX(cfgstat_lock);
+ int ret = 0, ret_override = 0;
+
+ if (mutex_lock_interruptible(&cfgstat_lock))
+ return -EINTR;
+
+again:
+ switch (st_req) {
+
+ /* cfgstat takes CLEAN, READY or SUSPEND,
+ while st_req can take SUSPEND in addition. */
+
+ case CFGSTAT_CLEAN:
+ if (cfgstat == CFGSTAT_CLEAN)
+ goto up_out;
+ if ((ret = dsp_uncfg()) < 0)
+ goto up_out;
+ break;
+
+ case CFGSTAT_READY:
+ if (cfgstat != CFGSTAT_CLEAN) {
+ printk(KERN_ERR "omapdsp: DSP is ready already!\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+
+ ret = dsp_cfg();
+ if (ret > 0) { /* failed, but state is clear. */
+ ret = -EINVAL;
+ goto up_out;
+ } else if (ret < 0) { /* failed, need cleanup. */
+ st_req = CFGSTAT_CLEAN;
+ ret_override = ret;
+ goto again;
+ }
+ break;
+
+ /*
+ * suspend / resume
+ * DSP is not reset within this code, but done in omap_pm_suspend.
+ * so if these functions are called from sysfs,
+ * DSP should be reset / unreset out of these functions.
+ */
+ case CFGSTAT_SUSPEND:
+ switch (cfgstat) {
+
+ case CFGSTAT_CLEAN:
+ if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+ printk(KERN_WARNING
+ "omapdsp: illegal operation -- trying "
+ "suspend DSP while it is running but "
+ "not configured.\n"
+ " Resetting DSP.\n");
+ dsp_cpustat_request(CPUSTAT_RESET);
+ ret = -EINVAL;
+ }
+ goto up_out;
+
+ case CFGSTAT_READY:
+ if ((ret = dsp_suspend()) < 0)
+ goto up_out;
+ break;
+
+ case CFGSTAT_SUSPEND:
+ goto up_out;
+
+ default:
+ BUG();
+
+ }
+
+ break;
+
+ case CFGSTAT_RESUME:
+ if (cfgstat != CFGSTAT_SUSPEND) {
+ printk(KERN_WARNING
+ "omapdsp: DSP resume request, but DSP is not in "
+ "suspend state.\n");
+ ret = -EINVAL;
+ goto up_out;
+ }
+ st_req = CFGSTAT_READY;
+ break;
+
+ default:
+ BUG();
+
+ }
+
+ cfgstat = st_req;
+up_out:
+ mutex_unlock(&cfgstat_lock);
+ return ret_override ? ret_override : ret;
+}
+
+enum cfgstat_e dsp_cfgstat_get_stat(void)
+{
+ return cfgstat;
+}
+
+/*
+ * polls all tasks
+ */
+static int dsp_poll(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: poll error!\n");
+
+ return ret;
+}
+
+int dsp_set_runlevel(u8 level)
+{
+ if (level == RUNLEVEL_RECOVERY) {
+ if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
+ return -EINVAL;
+ } else {
+ if ((level < RUNLEVEL_USER) ||
+ (level > RUNLEVEL_SUPER))
+ return -EINVAL;
+ if (mbcompose_send(RUNLEVEL, level, 0) < 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static void dsp_fbctl_enable(void)
+{
+ mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+ int ret;
+
+ ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
+ NULL);
+ if ((ret < 0) && (ret != -EINTR))
+ printk(KERN_ERR "omapdsp: fb disable error!\n");
+
+ return 0;
+}
+
+static int dsp_fbstat_request(enum fbstat_e st)
+{
+ static DEFINE_MUTEX(fbstat_lock);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&fbstat_lock))
+ return -EINTR;
+
+ if (st == fbstat)
+ goto up_out;
+
+ switch (st) {
+ case FBSTAT_ENABLED:
+ dsp_fbctl_enable();
+ break;
+ case FBSTAT_DISABLED:
+ if ((ret = dsp_fbctl_disable()) < 0)
+ goto up_out;
+ break;
+ default:
+ BUG();
+ }
+
+ fbstat = st;
+up_out:
+ mutex_unlock(&fbstat_lock);
+ return 0;
+}
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+/*
+ * DSP control device file operations
+ */
+static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ /*
+ * command level 1: commands which don't need lock
+ */
+ case DSPCTL_IOCTL_RUN:
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case DSPCTL_IOCTL_RESET:
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case DSPCTL_IOCTL_SETRSTVECT:
+ ret = dsp_set_rstvect((dsp_long_t)arg);
+ break;
+
+#ifdef CONFIG_ARCH_OMAP1
+ case DSPCTL_IOCTL_CPU_IDLE:
+ dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+ break;
+
+ case DSPCTL_IOCTL_GBL_IDLE:
+ dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+ break;
+
+ case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
+ mpui_wordswap_on();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
+ mpui_wordswap_off();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
+ mpui_byteswap_on();
+ break;
+
+ case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
+ mpui_byteswap_off();
+ break;
+#endif /* CONFIG_ARCH_OMAP1 */
+
+ case DSPCTL_IOCTL_TASKCNT:
+ ret = dsp_task_count();
+ break;
+
+ case DSPCTL_IOCTL_MBSEND:
+ {
+ struct omap_dsp_mailbox_cmd u_cmd;
+ mbox_msg_t msg;
+ if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+ return -EFAULT;
+ msg = (u_cmd.cmd << 16) | u_cmd.data;
+ ret = dsp_mbcmd_send((struct mbcmd *)&msg);
+ break;
+ }
+
+ case DSPCTL_IOCTL_SETVAR:
+ {
+ struct omap_dsp_varinfo var;
+ if (copy_from_user(&var, (void *)arg, sizeof(var)))
+ return -EFAULT;
+ ret = dsp_setvar(var.varid, var.val[0]);
+ break;
+ }
+
+ case DSPCTL_IOCTL_RUNLEVEL:
+ ret = dsp_set_runlevel(arg);
+ break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case DSPCTL_IOCTL_FBEN:
+ ret = dsp_fbstat_request(FBSTAT_ENABLED);
+ break;
+#endif
+
+ /*
+ * command level 2: commands which need lock
+ */
+ case DSPCTL_IOCTL_DSPCFG:
+ ret = dsp_cfgstat_request(CFGSTAT_READY);
+ break;
+
+ case DSPCTL_IOCTL_DSPUNCFG:
+ ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
+ break;
+
+ case DSPCTL_IOCTL_POLL:
+ ret = dsp_poll();
+ break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case DSPCTL_IOCTL_FBDIS:
+ ret = dsp_fbstat_request(FBSTAT_DISABLED);
+ break;
+#endif
+
+ case DSPCTL_IOCTL_SUSPEND:
+ if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RESET);
+ break;
+
+ case DSPCTL_IOCTL_RESUME:
+ if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
+ break;
+ dsp_cpustat_request(CPUSTAT_RUN);
+ break;
+
+ case DSPCTL_IOCTL_REGMEMR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ u16 adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+ return -EFAULT;
+ if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+ return -EFAULT;
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGMEMW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGIOR:
+ {
+ struct omap_dsp_reginfo *u_reg = (void *)arg;
+ u16 adr, val;
+
+ if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+ return -EFAULT;
+ if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
+ return ret;
+ if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+ return -EFAULT;
+ break;
+ }
+
+ case DSPCTL_IOCTL_REGIOW:
+ {
+ struct omap_dsp_reginfo reg;
+
+ if (copy_from_user(®, (void *)arg, sizeof(reg)))
+ return -EFAULT;
+ ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
+ break;
+ }
+
+ case DSPCTL_IOCTL_GETVAR:
+ {
+ struct omap_dsp_varinfo *u_var = (void *)arg;
+ u8 varid;
+ u16 val[5]; /* maximum */
+ int argc;
+
+ if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
+ return -EFAULT;
+ switch (varid) {
+ case VARID_ICRMASK:
+ argc = 1;
+ break;
+ case VARID_LOADINFO:
+ argc = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if ((ret = dsp_getvar(varid, val)) < 0)
+ return ret;
+ if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_suspend(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_dspcfg(struct mbcmd *mb)
+{
+ u8 last = mb->cmd_l & 0x80;
+ u8 cfgcmd = mb->cmd_l & 0x7f;
+ static dsp_long_t tmp_ipb_adr;
+
+ if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+ (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
+ printk(KERN_WARNING
+ "mbox: DSPCFG command received, "
+ "but nobody is waiting for it...\n");
+ return;
+ }
+
+ /* mailbox protocol check */
+ if (cfgcmd == DSPCFG_PROTREV) {
+ mbox_revision = mb->data;
+ if (mbox_revision == MBPROT_REVISION)
+ return;
+#ifdef OLD_BINARY_SUPPORT
+ else if ((mbox_revision == MBREV_3_0) ||
+ (mbox_revision == MBREV_3_2)) {
+ printk(KERN_WARNING
+ "mbox: ***** old DSP binary *****\n"
+ " Please update your DSP application.\n");
+ return;
+ }
+#endif
+ else {
+ printk(KERN_ERR
+ "mbox: protocol revision check error!\n"
+ " expected=0x%04x, received=0x%04x\n",
+ MBPROT_REVISION, mb->data);
+ mbox_revision = -1;
+ goto abort1;
+ }
+ }
+
+ /*
+ * following commands are accepted only after
+ * revision check has been passed.
+ */
+ if (!mbox_revision < 0) {
+ pr_info("mbox: DSPCFG command received, "
+ "but revision check has not been passed.\n");
+ return;
+ }
+
+ switch (cfgcmd) {
+ case DSPCFG_SYSADRH:
+ tmp_ipb_adr = (u32)mb->data << 16;
+ break;
+
+ case DSPCFG_SYSADRL:
+ tmp_ipb_adr |= mb->data;
+ break;
+
+ case DSPCFG_ABORT:
+ goto abort1;
+
+ default:
+ printk(KERN_ERR
+ "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+ mb->cmd_l, mb->data);
+ return;
+ }
+
+ if (last) {
+ void *badr;
+ u16 bln;
+ u16 bsz;
+ volatile u16 *buf;
+ void *ipb_sys_da, *ipb_sys_ad;
+ void *mbseq; /* FIXME: 3.4 obsolete */
+ short *dbg_buf;
+ u16 dbg_buf_sz, dbg_line_sz;
+ struct mem_sync_struct mem_sync, *mem_syncp;
+
+ ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+ if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+ goto abort1;
+
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
+ goto abort1;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+ printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto abort1;
+ }
+ /*
+ * read configuration data on system IPBUF
+ * we must read with 16bit-access
+ */
+#ifdef OLD_BINARY_SUPPORT
+ if (mbox_revision == MBPROT_REVISION) {
+#endif
+ 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 = 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 (mbox_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 (mbox_revision == MBREV_3_0) {
+ buf = ipbuf_sys_da->d;
+ 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 */
+ dsp_mem_disable(ipbuf_sys_da);
+ goto abort1;
+ }
+#endif /* OLD_BINARY_SUPPORT */
+
+ release_ipbuf_pvt(ipbuf_sys_da);
+ dsp_mem_disable(ipbuf_sys_da);
+
+ /*
+ * 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_mbox_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;
+
+ misc_mb_wait.cmd_h = 0;
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ }
+ return;
+
+abort2:
+ ipbuf_stop();
+abort1:
+ wake_up_interruptible(&misc_mb_wait.wait_q);
+ return;
+}
+
+void mbox_poll(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_regrw(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case REGRW_DATA:
+ misc_mbcmd_response(mb, 1, 0);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Illegal REGRW command: "
+ "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+ return;
+ }
+}
+
+void mbox_getvar(struct mbcmd *mb)
+{
+ switch (mb->cmd_l) {
+ case VARID_ICRMASK:
+ misc_mbcmd_response(mb, 1, 1);
+ break;
+ case VARID_LOADINFO:
+ misc_mbcmd_response(mb, 5, 1);
+ break;
+ default:
+ printk(KERN_ERR
+ "mbox: Illegal GETVAR command: "
+ "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+ return;
+ }
+}
+
+void mbox_fbctl_disable(struct mbcmd *mb)
+{
+ misc_mbcmd_response(mb, 0, 0);
+}
+
+struct file_operations dsp_ctl_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dsp_ctl_ioctl,
+};
+
+/*
+ * sysfs files
+ */
+
+/* ifver */
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+
+ /*
+ * I/F VERSION descriptions:
+ *
+ * 3.2: sysfs / udev support
+ * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+ * 3.3: added following ioctls
+ * DSPCTL_IOCTL_GBL_IDLE
+ * DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
+ * DSPCTL_IOCTL_POLL
+ */
+
+ /*
+ * print all supporting I/F VERSIONs, like followings.
+ *
+ * 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;
+}
+
+/* cpustat */
+static char *cpustat_name[CPUSTAT_MAX] = {
+ [CPUSTAT_RESET] = "reset",
+#ifdef CONFIG_ARCH_OMAP1
+ [CPUSTAT_GBL_IDLE] = "gbl_idle",
+ [CPUSTAT_CPU_IDLE] = "cpu_idle",
+#endif
+ [CPUSTAT_RUN] = "run",
+};
+
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
+}
+
+/* icrmask */
+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)
+{
+ u16 mask;
+ int ret;
+
+ mask = simple_strtol(buf, NULL, 16);
+ dsp_cpustat_set_icrmask(mask);
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+ ret = dsp_setvar(VARID_ICRMASK, mask);
+ if (ret < 0)
+ return ret;
+ }
+
+ return count;
+}
+
+/* loadinfo */
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len;
+ int ret;
+ u16 val[5];
+
+ if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
+ return ret;
+
+ /*
+ * load info value range is 0(free) - 10000(busy):
+ * if CPU load is not measured on DSP, it sets 0xffff at val[0].
+ */
+
+ if (val[0] == 0xffff) {
+ len = sprintf(buf,
+ "currently DSP load info is not available.\n");
+ goto out;
+ }
+
+ len = sprintf(buf,
+ "DSP load info:\n"
+ " 10ms average = %3d.%02d%%\n"
+ " 1sec average = %3d.%02d%% busiest 10ms = %3d.%02d%%\n"
+ " 1min average = %3d.%02d%% busiest 1s = %3d.%02d%%\n",
+ val[0]/100, val[0]%100,
+ val[1]/100, val[1]%100, val[2]/100, val[2]%100,
+ val[3]/100, val[3]%100, val[4]/100, val[4]%100);
+out:
+ return len;
+}
+
+int __init dsp_ctl_init(void)
+{
+ int ret;
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+ if (unlikely(ret))
+ return ret;
+ ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+ if (unlikely(ret))
+ goto fail_create_cpustat;
+ ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+ if (unlikely(ret))
+ goto fail_create_icrmask;
+
+ return 0;
+
+fail_create_icrmask:
+ device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+fail_create_cpustat:
+ device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+
+ return ret;
+}
+
+void dsp_ctl_exit(void)
+{
+ device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+ device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+ device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
+}
diff --git a/drivers/dsp/dspgateway/dsp_ctl_core.c b/drivers/dsp/dspgateway/dsp_ctl_core.c
new file mode 100644
index 0000000..956ef26
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_ctl_core.c
@@ -0,0 +1,132 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include "dsp.h"
+
+#define CTL_MINOR 0
+#define MEM_MINOR 1
+#define TWCH_MINOR 2
+#define ERR_MINOR 3
+
+static struct class *dsp_ctl_class;
+extern struct file_operations dsp_ctl_fops,
+ dsp_mem_fops,
+ dsp_twch_fops,
+ dsp_err_fops;
+
+static int dsp_ctl_core_open(struct inode *inode, struct file *file)
+{
+ static DEFINE_MUTEX(open_lock);
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&open_lock))
+ return -EINTR;
+ if (omap_dsp->initialized == 0) {
+ ret = dsp_late_init();
+ if (ret != 0) {
+ mutex_unlock(&open_lock);
+ return ret;
+ }
+ omap_dsp->initialized = 1;
+ }
+ mutex_unlock(&open_lock);
+
+ switch (iminor(inode)) {
+ case CTL_MINOR:
+ file->f_op = &dsp_ctl_fops;
+ break;
+ case MEM_MINOR:
+ file->f_op = &dsp_mem_fops;
+ break;
+ case TWCH_MINOR:
+ file->f_op = &dsp_twch_fops;
+ break;
+ case ERR_MINOR:
+ file->f_op = &dsp_err_fops;
+ break;
+ default:
+ return -ENXIO;
+ }
+ if (file->f_op && file->f_op->open)
+ return file->f_op->open(inode, file);
+ return 0;
+}
+
+static struct file_operations dsp_ctl_core_fops = {
+ .owner = THIS_MODULE,
+ .open = dsp_ctl_core_open,
+};
+
+static const struct dev_list {
+ unsigned int minor;
+ char *devname;
+ umode_t mode;
+} dev_list[] = {
+ {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)
+{
+ int retval;
+ int i;
+
+ retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
+ &dsp_ctl_core_fops);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "omapdsp: failed to register dspctl device: %d\n",
+ retval);
+ return retval;
+ }
+
+ dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
+ for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+ device_create(dsp_ctl_class, NULL,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor),
+ dev_list[i].devname);
+ }
+
+ return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+ device_destroy(dsp_ctl_class,
+ MKDEV(OMAP_DSP_CTL_MAJOR,
+ dev_list[i].minor));
+ }
+ class_destroy(dsp_ctl_class);
+
+ unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
diff --git a/drivers/dsp/dspgateway/dsp_mbcmd.h b/drivers/dsp/dspgateway/dsp_mbcmd.h
new file mode 100644
index 0000000..fb35749
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_mbcmd.h
@@ -0,0 +1,147 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_MBCMD_H
+#define __PLAT_OMAP_DSP_MBCMD_H
+/*
+ * mailbox command: 0x00 - 0x7f
+ * when a driver wants to use mailbox, it must reserve mailbox commands here.
+ */
+#define MBOX_CMD_DSP_WDSND 0x10
+#define MBOX_CMD_DSP_WDREQ 0x11
+#define MBOX_CMD_DSP_BKSND 0x20
+#define MBOX_CMD_DSP_BKREQ 0x21
+#define MBOX_CMD_DSP_BKYLD 0x23
+#define MBOX_CMD_DSP_BKSNDP 0x24
+#define MBOX_CMD_DSP_BKREQP 0x25
+#define MBOX_CMD_DSP_TCTL 0x30
+#define MBOX_CMD_DSP_TCTLDATA 0x31
+#define MBOX_CMD_DSP_POLL 0x32
+#define MBOX_CMD_DSP_WDT 0x50
+#define MBOX_CMD_DSP_RUNLEVEL 0x51
+#define MBOX_CMD_DSP_PM 0x52
+#define MBOX_CMD_DSP_SUSPEND 0x53
+#define MBOX_CMD_DSP_KFUNC 0x54
+#define MBOX_CMD_DSP_TCFG 0x60
+#define MBOX_CMD_DSP_TADD 0x62
+#define MBOX_CMD_DSP_TDEL 0x63
+#define MBOX_CMD_DSP_TSTOP 0x65
+#define MBOX_CMD_DSP_DSPCFG 0x70
+#define MBOX_CMD_DSP_REGRW 0x72
+#define MBOX_CMD_DSP_GETVAR 0x74
+#define MBOX_CMD_DSP_SETVAR 0x75
+#define MBOX_CMD_DSP_ERR 0x78
+#define MBOX_CMD_DSP_DBG 0x79
+
+/*
+ * DSP mailbox protocol definitions
+ */
+#define MBPROT_REVISION 0x0019
+
+#define TCTL_TINIT 0x0000
+#define TCTL_TEN 0x0001
+#define TCTL_TDIS 0x0002
+#define TCTL_TCLR 0x0003
+#define TCTL_TCLR_FORCE 0x0004
+
+#define RUNLEVEL_USER 0x01
+#define RUNLEVEL_SUPER 0x0e
+#define RUNLEVEL_RECOVERY 0x10
+
+#define PM_DISABLE 0x00
+#define PM_ENABLE 0x01
+
+#define KFUNC_FBCTL 0x00
+#define KFUNC_POWER 0x01
+
+#define FBCTL_UPD 0x0000
+#define FBCTL_ENABLE 0x0002
+#define FBCTL_DISABLE 0x0003
+
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP 0x0000 /* ARM(exe/ack) <-> DSP(req) */
+#define AUDIO_PWR_DOWN 0x0001 /* ARM(exe) <- DSP(req) */
+#define AUDIO_PWR_DOWN1 AUDIO_PWR_DOWN
+#define AUDIO_PWR_DOWN2 0x0002
+#define DSP_PWR_UP 0x0003 /* ARM(exe/snd) -> DSP(exe) */
+#define DSP_PWR_DOWN 0x0004 /* ARM(exe) <- DSP(req) */
+#define DVFS_START 0x0006 /* ARM(req) <-> DSP(exe/ack)*/
+#define DVFS_STOP 0x0007 /* ARM(req) -> DSP(exe) */
+
+#define TDEL_SAFE 0x0000
+#define TDEL_KILL 0x0001
+
+#define DSPCFG_REQ 0x00
+#define DSPCFG_SYSADRH 0x28
+#define DSPCFG_SYSADRL 0x29
+#define DSPCFG_PROTREV 0x70
+#define DSPCFG_ABORT 0x78
+#define DSPCFG_LAST 0x80
+
+#define REGRW_MEMR 0x00
+#define REGRW_MEMW 0x01
+#define REGRW_IOR 0x02
+#define REGRW_IOW 0x03
+#define REGRW_DATA 0x04
+
+#define VARID_ICRMASK 0x00
+#define VARID_LOADINFO 0x01
+
+#define TTYP_ARCV 0x0001
+#define TTYP_ASND 0x0002
+#define TTYP_BKMD 0x0004
+#define TTYP_BKDM 0x0008
+#define TTYP_PVMD 0x0010
+#define TTYP_PVDM 0x0020
+
+#define EID_BADTID 0x10
+#define EID_BADTCN 0x11
+#define EID_BADBID 0x20
+#define EID_BADCNT 0x21
+#define EID_NOTLOCKED 0x22
+#define EID_STVBUF 0x23
+#define EID_BADADR 0x24
+#define EID_BADTCTL 0x30
+#define EID_BADPARAM 0x50
+#define EID_FATAL 0x58
+#define EID_NOMEM 0xc0
+#define EID_NORES 0xc1
+#define EID_IPBFULL 0xc2
+#define EID_WDT 0xd0
+#define EID_TASKNOTRDY 0xe0
+#define EID_TASKBSY 0xe1
+#define EID_TASKERR 0xef
+#define EID_BADCFGTYP 0xf0
+#define EID_DEBUG 0xf8
+#define EID_BADSEQ 0xfe
+#define EID_BADCMD 0xff
+
+#define TNM_LEN 16
+
+#define TID_FREE 0xff
+#define TID_ANON 0xfe
+
+#define BID_NULL 0xffff
+#define BID_PVT 0xfffe
+
+#endif /* __PLAT_OMAP_DSP_MBCMD_H */
diff --git a/drivers/dsp/dspgateway/dsp_mem.c b/drivers/dsp/dspgateway/dsp_mem.c
new file mode 100644
index 0000000..6d3148f
--- /dev/null
+++ b/drivers/dsp/dspgateway/dsp_mem.c
@@ -0,0 +1,484 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * Conversion to mempool API and ARM MMU section mapping
+ * by Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/dsp.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/mmu.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+#if 0
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../../mach-omap2/mmu.h"
+#endif
+#endif
+
+#include "mmu.h"
+
+static struct mem_sync_struct mem_sync;
+
+int dsp_mem_sync_inc(void)
+{
+ if (dsp_mem_enable((void *)dspmem_base) < 0)
+ return -1;
+ 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_disable((void *)dspmem_base);
+
+ return 0;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbox1 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;
+}
+
+
+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(&dsp_mmu.exmap_sem);
+ if (exmap_valid(&dsp_mmu, vadr, len))
+ ret = MEM_TYPE_EXTERN;
+ else
+ ret = MEM_TYPE_NONE;
+ up_read(&dsp_mmu.exmap_sem);
+ return ret;
+ }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+ char s[64];
+ va_list args;
+
+ if (dsp_mem_type(p, len) > 0)
+ return 0;
+
+ if (fmt == NULL)
+ goto out;
+
+ 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 external memory\n"
+ "space where no actual memory is mapped)\n", s, p, len);
+ out:
+ return -1;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+
+static inline unsigned long lineup_offset(unsigned long adr,
+ unsigned long ref,
+ unsigned long mask)
+{
+ unsigned long newadr;
+
+ newadr = (adr & ~mask) | (ref & mask);
+ if (newadr < adr)
+ newadr += mask + 1;
+ return newadr;
+}
+
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(struct work_struct *unused)
+{
+ int status;
+
+ status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
+ if (status == 0)
+ return;
+
+ /* FIXME: DSP is busy !! */
+ printk(KERN_ERR
+ "omapdsp:"
+ "DSP is busy when trying to send FBCTL:UPD response!\n");
+}
+
+static DECLARE_WORK(fbupd_response_work, fbupd_response);
+
+static void fbupd_cb(void *arg)
+{
+ schedule_work(&fbupd_response_work);
+}
+
+void mbox_fbctl_upd(void)
+{
+ struct omapfb_update_window win;
+ volatile unsigned short *buf = ipbuf_sys_da->d;
+
+ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
+ printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
+ return;
+ }
+ win.x = buf[0];
+ win.y = buf[1];
+ win.width = buf[2];
+ win.height = buf[3];
+ win.format = buf[4];
+ release_ipbuf_pvt(ipbuf_sys_da);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ if (!omapfb_ready) {
+ printk(KERN_WARNING
+ "omapdsp: fbupd() called while HWA742 is not ready!\n");
+ return;
+ }
+#endif
+ omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+ unsigned long event, void *fbi)
+{
+ pr_info("omapfb_notifier_cb(): event = %s\n",
+ (event == OMAPFB_EVENT_READY) ? "READY" :
+ (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+ if (event == OMAPFB_EVENT_READY)
+ omapfb_ready = 1;
+ else if (event == OMAPFB_EVENT_DISABLED)
+ omapfb_ready = 0;
+ return 0;
+}
+#endif
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+ dsp_long_t dspadr_actual;
+ unsigned long padr_sys, padr, fbsz_sys, fbsz;
+ int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ int status;
+#endif
+
+ pr_debug( "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ if (omapfb_nb) {
+ printk(KERN_WARNING
+ "omapdsp: frame buffer has been exported already!\n");
+ return -EBUSY;
+ }
+#endif
+
+ if (num_registered_fb == 0) {
+ pr_info("omapdsp: frame buffer not registered.\n");
+ return -EINVAL;
+ }
+ if (num_registered_fb != 1) {
+ pr_info("omapdsp: %d frame buffers found. we use first one.\n",
+ num_registered_fb);
+ }
+ padr_sys = registered_fb[0]->fix.smem_start;
+ fbsz_sys = registered_fb[0]->fix.smem_len;
+ if (fbsz_sys == 0) {
+ printk(KERN_ERR
+ "omapdsp: framebuffer doesn't seem to be configured "
+ "correctly! (size=0)\n");
+ return -EINVAL;
+ }
+
+ /*
+ * align padr and fbsz to 4kB boundary
+ * (should be noted to the user afterwards!)
+ */
+ padr = padr_sys & ~(SZ_4K-1);
+ fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
+
+ /* line up dspadr offset with padr */
+ dspadr_actual =
+ (fbsz > SZ_1M) ? lineup_offset(*dspadr, padr, SZ_1M-1) :
+ (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
+ /* (fbsz > SZ_4KB) ? */ *dspadr;
+ if (dspadr_actual != *dspadr)
+ pr_debug(
+ "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+ dspadr_actual);
+ *dspadr = dspadr_actual;
+
+ cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz,
+ EXMAP_TYPE_FB);
+ if (cnt < 0) {
+ printk(KERN_ERR "omapdsp: exmap failure.\n");
+ return cnt;
+ }
+
+ if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+ printk(KERN_WARNING
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+" !! screen base address or size is not aligned in 4kB: !!\n"
+" !! actual screen adr = %08lx, size = %08lx !!\n"
+" !! exporting adr = %08lx, size = %08lx !!\n"
+" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n"
+" !! Otherwise DSP can corrupt the kernel memory. !!\n"
+" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+ padr_sys, fbsz_sys, padr, fbsz);
+ }
+
+ /* increase the DMA priority */
+ set_emiff_dma_prio(15);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+ if (omapfb_nb == NULL) {
+ printk(KERN_ERR
+ "omapdsp: failed to allocate memory for omapfb_nb!\n");
+ omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
+ return -ENOMEM;
+ }
+
+ status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+ if (status)
+ pr_info("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+ return cnt;
+}
+#else
+void mbox_fbctl_upd(void) { }
+#endif
+
+/* dsp/mem fops: backward compatibility */
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct bin_attribute attr;
+
+ return __omap_mmu_mem_read(&dsp_mmu, &attr,
+ (char __user *)buf, *ppos, count);
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct bin_attribute attr;
+
+ return __omap_mmu_mem_write(&dsp_mmu, &attr,
+ (char __user *)buf, *ppos, count);
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct omap_dsp_mapinfo mapinfo;
+ __u32 size;
+
+ switch (cmd) {
+ case MEM_IOCTL_MMUINIT:
+ if (dsp_mmu.exmap_tbl)
+ omap_mmu_unregister(&dsp_mmu);
+ dsp_mem_ipi_init();
+ return omap_mmu_register(&dsp_mmu);
+
+ case MEM_IOCTL_EXMAP:
+ if (copy_from_user(&mapinfo, (void __user *)arg,
+ sizeof(mapinfo)))
+ return -EFAULT;
+ return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
+ 0, mapinfo.size, EXMAP_TYPE_MEM);
+
+ case MEM_IOCTL_EXUNMAP:
+ return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
+
+ case MEM_IOCTL_EXMAP_FLUSH:
+ omap_mmu_exmap_flush(&dsp_mmu);
+ return 0;
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+ case MEM_IOCTL_FBEXPORT:
+ {
+ dsp_long_t dspadr;
+ int ret;
+ if (copy_from_user(&dspadr, (void __user *)arg,
+ sizeof(dsp_long_t)))
+ return -EFAULT;
+ ret = dsp_fbexport(&dspadr);
+ if (copy_to_user((void __user *)arg, &dspadr,
+ sizeof(dsp_long_t)))
+ return -EFAULT;
+ return ret;
+ }
+#endif
+ case MEM_IOCTL_MMUITACK:
+ return dsp_mmu_itack();
+
+ case MEM_IOCTL_KMEM_RESERVE:
+
+ if (copy_from_user(&size, (void __user *)arg,
+ sizeof(__u32)))
+ return -EFAULT;
+ return omap_mmu_kmem_reserve(&dsp_mmu, size);
+
+
+ case MEM_IOCTL_KMEM_RELEASE:
+ omap_mmu_kmem_release();
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+struct file_operations dsp_mem_fops = {
+ .owner = THIS_MODULE,
+ .read = dsp_mem_read,
+ .write = dsp_mem_write,
+ .ioctl = dsp_mem_ioctl,
+};
+
+void dsp_mem_start(void)
+{
+ 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();
+}
+
+static void dsp_mmu_irq_work(struct work_struct *work)
+{
+ struct omap_mmu *mmu = container_of(work, struct omap_mmu, irq_work);
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+ dsp_err_set(ERRCODE_MMU, mmu->fault_address);
+ return;
+ }
+ omap_mmu_itack(mmu);
+ pr_info("Resetting DSP...\n");
+ dsp_cpustat_request(CPUSTAT_RESET);
+ omap_mmu_enable(mmu, 0);
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+int dsp_mem_late_init(void)
+{
+ int ret;
+
+ dsp_mem_ipi_init();
+
+ INIT_WORK(&dsp_mmu.irq_work, dsp_mmu_irq_work);
+ ret = omap_mmu_register(&dsp_mmu);
+ if (ret) {
+ dsp_reset_idle_boot_base();
+ goto out;
+ }
+ omap_dsp->mmu = &dsp_mmu;
+ out:
+ return ret;
+}
+
+int __init dsp_mem_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+ dsp_mmu.clk = dsp_fck_handle;
+ dsp_mmu.memclk = dsp_ick_handle;
+#elif defined(CONFIG_ARCH_OMAP1)
+ dsp_mmu.clk = dsp_ck_handle;
+ dsp_mmu.memclk = api_ck_handle;
+#endif
+ return 0;
+}
+
+void dsp_mem_exit(void)
+{
+ dsp_reset_idle_boot_base();
+ omap_mmu_unregister(&dsp_mmu);
+}
diff --git a/drivers/dsp/dspgateway/error.c b/drivers/dsp/dspgateway/error.c
new file mode 100644
index 0000000..d2276f9
--- /dev/null
+++ b/drivers/dsp/dspgateway/error.c
@@ -0,0 +1,227 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+/*
+ * value seen through read()
+ */
+#define DSP_ERR_WDT 0x00000001
+#define DSP_ERR_MMU 0x00000002
+static unsigned long errval;
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static int errcnt;
+static u16 wdtval; /* FIXME: read through ioctl */
+static u32 mmu_fadr; /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long flags;
+ int status;
+ DEFINE_WAIT(wait);
+
+ if (count < 4)
+ return 0;
+
+ prepare_to_wait(&err_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (errcnt == 0)
+ schedule();
+ finish_wait(&err_wait_q, &wait);
+ if (signal_pending(current))
+ return -EINTR;
+
+ local_irq_save(flags);
+ status = copy_to_user(buf, &errval, 4);
+ if (status) {
+ local_irq_restore(flags);
+ return -EFAULT;
+ }
+ errcnt = 0;
+ local_irq_restore(flags);
+
+ return 4;
+}
+
+static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(file, &err_wait_q, wait);
+ if (errcnt != 0)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+struct file_operations dsp_err_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_err_poll,
+ .read = dsp_err_read,
+};
+
+/*
+ * set / clear functions
+ */
+
+/* DSP MMU */
+static void dsp_err_mmu_set(unsigned long arg)
+{
+ disable_irq(omap_dsp->mmu->irq);
+ mmu_fadr = (u32)arg;
+}
+
+static void dsp_err_mmu_clr(void)
+{
+ enable_irq(omap_dsp->mmu->irq);
+}
+
+/* WDT */
+static void dsp_err_wdt_set(unsigned long arg)
+{
+ wdtval = (u16)arg;
+}
+
+/*
+ * error code handler
+ */
+static struct {
+ unsigned long val;
+ void (*set)(unsigned long arg);
+ void (*clr)(void);
+} dsp_err_desc[ERRCODE_MAX] = {
+ [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
+ [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
+};
+
+void dsp_err_set(enum errcode_e code, unsigned long arg)
+{
+ if (dsp_err_desc[code].set != NULL)
+ dsp_err_desc[code].set(arg);
+
+ errval |= dsp_err_desc[code].val;
+ errcnt++;
+ wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_clear(enum errcode_e code)
+{
+ errval &= ~dsp_err_desc[code].val;
+
+ if (dsp_err_desc[code].clr != NULL)
+ dsp_err_desc[code].clr();
+}
+
+int dsp_err_isset(enum errcode_e code)
+{
+ return (errval & dsp_err_desc[code].val) ? 1 : 0;
+}
+
+void dsp_err_notify(void)
+{
+ /* new error code should be assigned */
+ dsp_err_set(DSP_ERR_WDT, 0);
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+static void mbox_err_wdt(u16 data)
+{
+ dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbox_wdt(struct mbcmd *mb)
+{
+ mbox_err_wdt(mb->data);
+}
+#endif
+
+extern void mbox_err_ipbfull(void);
+extern void mbox_err_fatal(u8 tid);
+
+void mbox_err(struct mbcmd *mb)
+{
+ u8 eid = mb->cmd_l;
+ char *eidnm = subcmd_name(mb);
+ u8 tid;
+
+ if (eidnm) {
+ printk(KERN_WARNING
+ "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+ } else {
+ printk(KERN_WARNING
+ "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
+ eid, mb->data);
+ }
+
+ switch (eid) {
+ case EID_IPBFULL:
+ mbox_err_ipbfull();
+ break;
+
+ case EID_FATAL:
+ tid = mb->data & 0x00ff;
+ mbox_err_fatal(tid);
+ break;
+
+ case EID_WDT:
+ mbox_err_wdt(mb->data);
+ break;
+ }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+ enum errcode_e i;
+
+ for (i = 0; i < ERRCODE_MAX; i++) {
+ if (dsp_err_isset(i))
+ dsp_err_clear(i);
+ }
+ omap_dsp->mbox->err_notify = dsp_err_notify;
+ errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+ wake_up_interruptible(&err_wait_q);
+ omap_dsp->mbox->err_notify = NULL;
+}
diff --git a/drivers/dsp/dspgateway/hardware_dsp.h b/drivers/dsp/dspgateway/hardware_dsp.h
new file mode 100644
index 0000000..5af46f8
--- /dev/null
+++ b/drivers/dsp/dspgateway/hardware_dsp.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_HARDWARE_DSP_H
+#define __OMAP_DSP_HARDWARE_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP1
+#include "omap1_dsp.h"
+#endif
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3430)
+#include "omap2_dsp.h"
+#endif
+
+#endif /* __OMAP_DSP_HARDWARE_DSP_H */
diff --git a/drivers/dsp/dspgateway/ipbuf.c b/drivers/dsp/dspgateway/ipbuf.c
new file mode 100644
index 0000000..aba8e74
--- /dev/null
+++ b/drivers/dsp/dspgateway/ipbuf.c
@@ -0,0 +1,353 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static struct ipbuf_head *g_ipbuf;
+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;
+
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
+void ipbuf_stop(void)
+{
+ int i;
+
+ device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
+
+ spin_lock(&ipb_free.lock);
+ RESET_IPBLINK(&ipb_free);
+ spin_unlock(&ipb_free.lock);
+
+ ipbcfg.ln = 0;
+ if (g_ipbuf) {
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
+ }
+ for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+ dsp_mem_disable((void *)daram_base);
+ }
+ ipbuf_sys_hold_mem_active = 0;
+}
+
+int ipbuf_config(u16 ln, u16 lsz, void *base)
+{
+ size_t lsz_byte = ((size_t)lsz) << 1;
+ size_t size;
+ int ret = 0;
+ int i;
+
+ /*
+ * global IPBUF
+ */
+ if (((unsigned long)base) & 0x3) {
+ printk(KERN_ERR
+ "omapdsp: global ipbuf address(0x%p) is not "
+ "32-bit aligned!\n", base);
+ return -EINVAL;
+ }
+ size = lsz_byte * ln;
+ if (dsp_address_validate(base, size, "global ipbuf") < 0)
+ return -EINVAL;
+
+ g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+ if (g_ipbuf == NULL) {
+ printk(KERN_ERR
+ "omapdsp: memory allocation for ipbuf failed.\n");
+ return -ENOMEM;
+ }
+ for (i = 0; i < ln; i++) {
+ void *top, *btm;
+
+ top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
+ btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
+ g_ipbuf[i].p = (struct ipbuf *)top;
+ g_ipbuf[i].bid = i;
+ if (((unsigned long)top & 0xfffe0000) !=
+ ((unsigned long)btm & 0xfffe0000)) {
+ /*
+ * an ipbuf line should not cross
+ * 64k-word boundary.
+ */
+ printk(KERN_ERR
+ "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
+ " @0x%p, size=0x%08x\n", i, top, lsz_byte);
+ ret = -EINVAL;
+ goto free_out;
+ }
+ }
+ ipbcfg.ln = ln;
+ ipbcfg.lsz = lsz;
+ ipbcfg.base = base;
+ ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
+ ipbcfg.cnt_full = 0;
+
+ pr_info("omapdsp: IPBUF configuration\n"
+ " %d words * %d lines at 0x%p.\n",
+ ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+ return ret;
+
+ free_out:
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
+ return ret;
+}
+
+int ipbuf_sys_config(void *p, arm_dsp_dir_t 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, arm_dsp_dir_t 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);
+}
+
+/*
+ * Global IPBUF operations
+ */
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
+{
+ return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+ struct ipbuf_head *ipb_h;
+
+ if (dsp_mem_enable_ipbuf() < 0)
+ return NULL;
+
+ spin_lock(&ipb_free.lock);
+
+ if (ipblink_empty(&ipb_free)) {
+ /* FIXME: wait on queue when not available. */
+ ipb_h = NULL;
+ goto out;
+ }
+ ipb_h = &g_ipbuf[ipb_free.top];
+ ipb_h->p->la = tid; /* lock */
+ __ipblink_del_top(&ipb_free);
+out:
+ spin_unlock(&ipb_free.lock);
+ dsp_mem_disable_ipbuf();
+
+ return ipb_h;
+}
+
+void release_ipbuf(struct ipbuf_head *ipb_h)
+{
+ if (ipb_h->p->la == TID_FREE) {
+ printk(KERN_WARNING
+ "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+ ipb_h->bid);
+ /*
+ * FIXME: re-calc bsycnt
+ */
+ return;
+ }
+ ipb_h->p->la = TID_FREE;
+ ipb_h->p->sa = TID_FREE;
+ ipblink_add_tail(&ipb_free, ipb_h->bid);
+}
+
+static int try_yld(struct ipbuf_head *ipb_h)
+{
+ int status;
+
+ ipb_h->p->sa = TID_ANON;
+ status = mbcompose_send(BKYLD, 0, ipb_h->bid);
+ if (status < 0) {
+ /* DSP is busy and ARM keeps this line. */
+ release_ipbuf(ipb_h);
+ return status;
+ }
+
+ ipb_bsycnt_inc(&ipbcfg);
+ return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(struct work_struct *unused)
+{
+ while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+ struct ipbuf_head *ipb_h;
+
+ if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
+ return;
+ if (try_yld(ipb_h) < 0)
+ return;
+ }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
+
+void balance_ipbuf(void)
+{
+ schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
+{
+ if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+ /* we don't have enough IPBUF lines. let's keep it. */
+ release_ipbuf(ipb_h);
+ } else {
+ /* we have enough IPBUF lines. let's return this line to DSP. */
+ ipb_h->p->la = TID_ANON;
+ try_yld(ipb_h);
+ balance_ipbuf();
+ }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
+{
+ release_ipbuf(ipb_h);
+ balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+
+void mbox_err_ipbfull(void)
+{
+ ipbcfg.cnt_full++;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+ u16 bid;
+
+ for (bid = 0; bid < ipbcfg.ln; bid++) {
+ struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+ u16 la = ipb_h->p->la;
+ u16 ld = ipb_h->p->ld;
+ u16 c = ipb_h->p->c;
+
+ if (len > PAGE_SIZE - 100) {
+ len += sprintf(buf + len, "out of buffer.\n");
+ goto finish;
+ }
+
+ len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
+ bid, ipb_h->p);
+ if (la == TID_FREE) {
+ len += sprintf(buf + len,
+ " DSPtask[%d]->Linux "
+ "(already read and now free for Linux)\n",
+ ld);
+ } else if (ld == TID_FREE) {
+ len += sprintf(buf + len,
+ " Linux->DSPtask[%d] "
+ "(already read and now free for DSP)\n",
+ la);
+ } else if (ipbuf_is_held(ld, bid)) {
+ len += sprintf(buf + len,
+ " DSPtask[%d]->Linux "
+ "(waiting to be read)\n"
+ " count = %d\n", ld, c);
+ } else {
+ len += sprintf(buf + len,
+ " Linux->DSPtask[%d] "
+ "(waiting to be read)\n"
+ " count = %d\n", la, c);
+ }
+ }
+
+ len += sprintf(buf + len, "\nFree IPBUF link: ");
+ spin_lock(&ipb_free.lock);
+ ipblink_for_each(bid, &ipb_free) {
+ len += sprintf(buf + len, "%d ", bid);
+ }
+ spin_unlock(&ipb_free.lock);
+ len += sprintf(buf + len, "\n");
+ len += sprintf(buf + len, "IPBFULL error count: %ld\n",
+ ipbcfg.cnt_full);
+
+finish:
+ return len;
+}
diff --git a/drivers/dsp/dspgateway/ipbuf.h b/drivers/dsp/dspgateway/ipbuf.h
new file mode 100644
index 0000000..926d353
--- /dev/null
+++ b/drivers/dsp/dspgateway/ipbuf.h
@@ -0,0 +1,193 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_IPBUF_H
+#define __PLAT_OMAP_DSP_IPBUF_H
+
+struct ipbuf {
+ u16 c; /* count */
+ u16 next; /* link */
+ u16 la; /* lock owner (ARM side) */
+ u16 sa; /* sync word (ARM->DSP) */
+ u16 ld; /* lock owner (DSP side) */
+ u16 sd; /* sync word (DSP->ARM) */
+ unsigned char d[0]; /* data */
+};
+
+struct ipbuf_p {
+ u16 c; /* count */
+ u16 s; /* sync word */
+ u16 al; /* data address lower */
+ u16 ah; /* data address upper */
+};
+
+#define IPBUF_SYS_DLEN 31
+
+struct ipbuf_sys {
+ u16 s; /* sync word */
+ u16 d[IPBUF_SYS_DLEN]; /* data */
+};
+
+struct ipbcfg {
+ u16 ln;
+ u16 lsz;
+ void *base;
+ u16 bsycnt;
+ unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+struct ipbuf_head {
+ u16 bid;
+ struct ipbuf *p;
+};
+
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg) atomic_inc((atomic_t *)&((ipbcfg)->bsycnt))
+#define ipb_bsycnt_dec(ipbcfg) atomic_dec((atomic_t *)&((ipbcfg)->bsycnt))
+
+#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;
+ u16 top;
+ u16 tail;
+};
+
+#define IPBLINK_INIT { \
+ .lock = SPIN_LOCK_UNLOCKED, \
+ .top = BID_NULL, \
+ .tail = BID_NULL, \
+ }
+
+#define INIT_IPBLINK(link) \
+ do { \
+ spin_lock_init(&(link)->lock); \
+ (link)->top = BID_NULL; \
+ (link)->tail = BID_NULL; \
+ } while(0)
+
+#define RESET_IPBLINK(link) \
+ do { \
+ (link)->top = BID_NULL; \
+ (link)->tail = BID_NULL; \
+ } while(0)
+
+#define ipblink_empty(link) ((link)->top == BID_NULL)
+
+static inline void __ipblink_del_top(struct ipblink *link)
+{
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
+
+ if ((link->top = ipb_h->p->next) == BID_NULL)
+ link->tail = BID_NULL;
+ else
+ ipb_h->p->next = BID_NULL;
+}
+
+static inline void ipblink_del_top(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_del_top(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+ if (ipblink_empty(link))
+ link->top = bid;
+ else
+ bid_to_ipbuf(link->tail)->p->next = bid;
+ link->tail = bid;
+}
+
+static inline void ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+ spin_lock(&link->lock);
+ __ipblink_add_tail(link, bid);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush(struct ipblink *link)
+{
+ u16 bid;
+
+ while (!ipblink_empty(link)) {
+ bid = link->top;
+ __ipblink_del_top(link);
+ unuse_ipbuf(bid_to_ipbuf(bid));
+ }
+}
+
+static inline void ipblink_flush(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_flush(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_pvt(struct ipblink *link)
+{
+ link->top = BID_PVT;
+ link->tail = BID_PVT;
+}
+
+static inline void ipblink_add_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_add_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_del_pvt(struct ipblink *link)
+{
+ link->top = BID_NULL;
+ link->tail = BID_NULL;
+}
+
+static inline void ipblink_del_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_del_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush_pvt(struct ipblink *link)
+{
+ if (!ipblink_empty(link))
+ ipblink_del_pvt(link);
+}
+
+static inline void ipblink_flush_pvt(struct ipblink *link)
+{
+ spin_lock(&link->lock);
+ __ipblink_flush_pvt(link);
+ spin_unlock(&link->lock);
+}
+
+#define ipblink_for_each(bid, link) \
+ for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
+
+#endif /* __PLAT_OMAP_DSP_IPBUF_H */
diff --git a/drivers/dsp/dspgateway/mblog.c b/drivers/dsp/dspgateway/mblog.c
new file mode 100644
index 0000000..2b1e113
--- /dev/null
+++ b/drivers/dsp/dspgateway/mblog.c
@@ -0,0 +1,280 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+char *subcmd_name(struct mbcmd *mb)
+{
+ u8 cmd_h = mb->cmd_h;
+ u8 cmd_l = mb->cmd_l;
+ char *s;
+
+ switch (cmd_h) {
+ case MBOX_CMD_DSP_RUNLEVEL:
+ s = (cmd_l == RUNLEVEL_USER) ? "USER":
+ (cmd_l == RUNLEVEL_SUPER) ? "SUPER":
+ (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_PM:
+ s = (cmd_l == PM_DISABLE) ? "DISABLE":
+ (cmd_l == PM_ENABLE) ? "ENABLE":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_KFUNC:
+ s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+ (cmd_l == KFUNC_POWER) ?
+ ((mb->data == AUDIO_PWR_UP) ? "PWR AUD /UP":
+ (mb->data == AUDIO_PWR_DOWN) ? "PWR AUD /DOWN":
+ (mb->data == AUDIO_PWR_DOWN2) ? "PWR AUD /DOWN(2)":
+ (mb->data == DSP_PWR_UP) ? "PWR DSP /UP":
+ (mb->data == DSP_PWR_DOWN) ? "PWR DSP /DOWN":
+ (mb->data == DVFS_START) ? "PWR DVFS/START":
+ (mb->data == DVFS_STOP) ? "PWR DVFS/STOP":
+ NULL):
+
+ NULL;
+ break;
+ case MBOX_CMD_DSP_DSPCFG:
+ {
+ u8 cfgc = cmd_l & 0x7f;
+ s = (cfgc == DSPCFG_REQ) ? "REQ":
+ (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
+ (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
+ (cfgc == DSPCFG_ABORT) ? "ABORT":
+ (cfgc == DSPCFG_PROTREV) ? "PROTREV":
+ NULL;
+ break;
+ }
+ case MBOX_CMD_DSP_REGRW:
+ s = (cmd_l == REGRW_MEMR) ? "MEMR":
+ (cmd_l == REGRW_MEMW) ? "MEMW":
+ (cmd_l == REGRW_IOR) ? "IOR":
+ (cmd_l == REGRW_IOW) ? "IOW":
+ (cmd_l == REGRW_DATA) ? "DATA":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_GETVAR:
+ case MBOX_CMD_DSP_SETVAR:
+ s = (cmd_l == VARID_ICRMASK) ? "ICRMASK":
+ (cmd_l == VARID_LOADINFO) ? "LOADINFO":
+ NULL;
+ break;
+ case MBOX_CMD_DSP_ERR:
+ s = (cmd_l == EID_BADTID) ? "BADTID":
+ (cmd_l == EID_BADTCN) ? "BADTCN":
+ (cmd_l == EID_BADBID) ? "BADBID":
+ (cmd_l == EID_BADCNT) ? "BADCNT":
+ (cmd_l == EID_NOTLOCKED) ? "NOTLOCKED":
+ (cmd_l == EID_STVBUF) ? "STVBUF":
+ (cmd_l == EID_BADADR) ? "BADADR":
+ (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":
+ (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
+ (cmd_l == EID_TASKBSY) ? "TASKBSY":
+ (cmd_l == EID_TASKERR) ? "TASKERR":
+ (cmd_l == EID_BADCFGTYP) ? "BADCFGTYP":
+ (cmd_l == EID_DEBUG) ? "DEBUG":
+ (cmd_l == EID_BADSEQ) ? "BADSEQ":
+ (cmd_l == EID_BADCMD) ? "BADCMD":
+ NULL;
+ break;
+ default:
+ s = NULL;
+ }
+
+ return s;
+}
+
+/* output of show() method should fit to PAGE_SIZE */
+#define MBLOG_DEPTH 64
+
+struct mblogent {
+ unsigned long jiffies;
+ mbox_msg_t msg;
+ arm_dsp_dir_t dir;
+};
+
+static struct {
+ spinlock_t lock;
+ int wp;
+ unsigned long cnt, cnt_ad, cnt_da;
+ struct mblogent ent[MBLOG_DEPTH];
+} mblog = {
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+ const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+ char *dir_str;
+ char *subname;
+
+ dir_str = (dir == DIR_A2D) ? "sending " : "receiving";
+ switch (ci->cmd_l_type) {
+ case CMD_L_TYPE_SUBCMD:
+ subname = subcmd_name(mb);
+ if (unlikely(!subname))
+ subname = "Unknown";
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, subname, mb->data);
+ break;
+ case CMD_L_TYPE_TID:
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, mb->cmd_l, mb->data);
+ break;
+ case CMD_L_TYPE_NULL:
+ pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
+ dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+ ci->name, mb->data);
+ break;
+ }
+}
+#else
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
+#endif
+
+void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+ struct mblogent *ent;
+
+ spin_lock(&mblog.lock);
+ ent = &mblog.ent[mblog.wp];
+ ent->jiffies = jiffies;
+ ent->msg = *(mbox_msg_t *)mb;
+ ent->dir = dir;
+ if (mblog.cnt < 0xffffffff)
+ mblog.cnt++;
+ switch (dir) {
+ case DIR_A2D:
+ if (mblog.cnt_ad < 0xffffffff)
+ mblog.cnt_ad++;
+ break;
+ case DIR_D2A:
+ if (mblog.cnt_da < 0xffffffff)
+ mblog.cnt_da++;
+ break;
+ }
+ if (++mblog.wp == MBLOG_DEPTH)
+ mblog.wp = 0;
+ spin_unlock(&mblog.lock);
+
+ mblog_print_cmd(mb, dir);
+}
+
+/*
+ * sysfs file
+ */
+static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int len = 0;
+ int wp;
+ int i;
+
+ spin_lock(&mblog.lock);
+
+ wp = mblog.wp;
+ len += sprintf(buf + len,
+ "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
+ mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
+ if (mblog.cnt == 0)
+ goto done;
+
+ len += sprintf(buf + len, " ARM->DSP ARM<-DSP\n");
+ len += sprintf(buf + len, " jiffies cmd data cmd data\n");
+ i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+ do {
+ struct mblogent *ent = &mblog.ent[i];
+ struct mbcmd *mb = (struct mbcmd *)&ent->msg;
+ char *subname;
+ struct cmdinfo ci_null = {
+ .name = "Unknown",
+ .cmd_l_type = CMD_L_TYPE_NULL,
+ };
+ const struct cmdinfo *ci;
+
+ len += sprintf(buf + len,
+ (ent->dir == DIR_A2D) ?
+ "%08lx %04x %04x ":
+ "%08lx %04x %04x ",
+ ent->jiffies,
+ (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
+
+ if ((ci = cmdinfo[mb->cmd_h]) == NULL)
+ ci = &ci_null;
+
+ switch (ci->cmd_l_type) {
+ case CMD_L_TYPE_SUBCMD:
+ if ((subname = subcmd_name(mb)) == NULL)
+ subname = "Unknown";
+ len += sprintf(buf + len, "%s:%s\n",
+ ci->name, subname);
+ break;
+ case CMD_L_TYPE_TID:
+ len += sprintf(buf + len, "%s:task %d\n",
+ ci->name, mb->cmd_l);
+ break;
+ case CMD_L_TYPE_NULL:
+ len += sprintf(buf + len, "%s\n", ci->name);
+ break;
+ }
+
+ if (++i == MBLOG_DEPTH)
+ i = 0;
+ } while (i != wp);
+
+done:
+ spin_unlock(&mblog.lock);
+
+ return len;
+}
+
+static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
+
+void __init mblog_init(void)
+{
+ int ret;
+
+ ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
+ if (ret)
+ printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void mblog_exit(void)
+{
+ device_remove_file(omap_dsp->dev, &dev_attr_mblog);
+}
diff --git a/drivers/dsp/dspgateway/mmu.h b/drivers/dsp/dspgateway/mmu.h
new file mode 100644
index 0000000..9d60e9e
--- /dev/null
+++ b/drivers/dsp/dspgateway/mmu.h
@@ -0,0 +1,140 @@
+#ifndef __PLAT_OMAP_DSP_MMU_H
+#define __PLAT_OMAP_DSP_MMU_H
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#ifdef CONFIG_ARCH_OMAP15XX
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = IO_ADDRESS(OMAP1510_DSP_MMU_BASE),
+ .membase = OMAP1510_DSP_BASE,
+ .memsize = OMAP1510_DSP_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_1510_DSP_MMU,
+ .ops = &omap1_mmu_ops,
+};
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = IO_ADDRESS(OMAP16XX_DSP_MMU_BASE),
+ .membase = OMAP16XX_DSP_BASE,
+ .memsize = OMAP16XX_DSP_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_1610_DSP_MMU,
+ .ops = &omap1_mmu_ops,
+};
+#endif
+#else /* OMAP2 */
+struct omap_mmu dsp_mmu = {
+ .name = "mmu:dsp",
+ .type = OMAP_MMU_DSP,
+ .base = DSP_MMU_24XX_VIRT,
+ .membase = DSP_MEM_24XX_VIRT,
+ .memsize = DSP_MEM_24XX_SIZE,
+ .nr_tlb_entries = 32,
+ .addrspace = 24,
+ .irq = INT_24XX_DSP_MMU,
+ .ops = &omap2_mmu_ops,
+};
+
+#define IOMAP_VAL 0x3f
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+/*
+ * OMAP1 EMIFF access
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define EMIF_PRIO_LB_MASK 0x0000f000
+#define EMIF_PRIO_LB_SHIFT 12
+#define EMIF_PRIO_DMA_MASK 0x00000f00
+#define EMIF_PRIO_DMA_SHIFT 8
+#define EMIF_PRIO_DSP_MASK 0x00000070
+#define EMIF_PRIO_DSP_SHIFT 4
+#define EMIF_PRIO_MPU_MASK 0x00000007
+#define EMIF_PRIO_MPU_SHIFT 0
+#define set_emiff_dma_prio(prio) \
+ do { \
+ omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
+ ~EMIF_PRIO_DMA_MASK) | \
+ ((prio) << EMIF_PRIO_DMA_SHIFT), \
+ OMAP_TC_OCPT1_PRIOR); \
+ } while(0)
+#else
+#define set_emiff_dma_prio(prio) do { } while (0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+ unsigned long dspadr;
+
+ pr_info("omapdsp: sending DSP MMU interrupt ack.\n");
+ if (!dsp_err_isset(ERRCODE_MMU)) {
+ printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+ return -EINVAL;
+ }
+ dspadr = dsp_mmu.fault_address & ~(SZ_4K-1);
+ /* FIXME: reserve TLB entry for this */
+ omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);
+ pr_info("omapdsp: falling into recovery runlevel...\n");
+ dsp_set_runlevel(RUNLEVEL_RECOVERY);
+ omap_mmu_itack(&dsp_mmu);
+ udelay(100);
+ omap_mmu_exunmap(&dsp_mmu, dspadr);
+ dsp_err_clear(ERRCODE_MMU);
+ return 0;
+}
+
+/*
+ * 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.
+ */
+static int intmem_enable(void)
+{
+ int ret = 0;
+
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+ ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
+
+ return ret;
+}
+
+static void intmem_disable(void) {
+ if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+ mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
+}
+#else
+static int intmem_enable(void) { return 0; }
+static void intmem_disable(void) { }
+static int dsp_mmu_itack(void) { return 0; }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static inline void dsp_mem_ipi_init(void)
+{
+ int i, dspmem_pg_count;
+ dspmem_pg_count = dspmem_size >> 12;
+ for (i = 0; i < dspmem_pg_count; i++) {
+ writel(i, DSP_IPI_INDEX);
+ writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
+ }
+ writel(1, DSP_IPI_ENABLE);
+ writel(IOMAP_VAL, DSP_IPI_IOMAP);
+}
+#else
+static inline void dsp_mem_ipi_init(void) { }
+#endif
+
+#endif /* __PLAT_OMAP_DSP_MMU_H */
diff --git a/drivers/dsp/dspgateway/omap1_dsp.h b/drivers/dsp/dspgateway/omap1_dsp.h
new file mode 100644
index 0000000..f4ec73e
--- /dev/null
+++ b/drivers/dsp/dspgateway/omap1_dsp.h
@@ -0,0 +1,114 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP1_DSP_H
+#define __OMAP_DSP_OMAP1_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP15XX
+#define OMAP1510_DARAM_BASE (OMAP1510_DSP_BASE + 0x0)
+#define OMAP1510_DARAM_SIZE 0x10000
+#define OMAP1510_SARAM_BASE (OMAP1510_DSP_BASE + 0x10000)
+#define OMAP1510_SARAM_SIZE 0x18000
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define OMAP16XX_DARAM_BASE (OMAP16XX_DSP_BASE + 0x0)
+#define OMAP16XX_DARAM_SIZE 0x10000
+#define OMAP16XX_SARAM_BASE (OMAP16XX_DSP_BASE + 0x10000)
+#define OMAP16XX_SARAM_SIZE 0x18000
+#endif
+
+/*
+ * Reset Control
+ */
+#define ARM_RSTCT1_SW_RST 0x0008
+#define ARM_RSTCT1_DSP_RST 0x0004
+#define ARM_RSTCT1_DSP_EN 0x0002
+#define ARM_RSTCT1_ARM_RST 0x0001
+
+/*
+ * MPUI
+ */
+#define MPUI_CTRL_WORDSWAP_MASK 0x00600000
+#define MPUI_CTRL_WORDSWAP_ALL 0x00000000
+#define MPUI_CTRL_WORDSWAP_NONAPI 0x00200000
+#define MPUI_CTRL_WORDSWAP_API 0x00400000
+#define MPUI_CTRL_WORDSWAP_NONE 0x00600000
+#define MPUI_CTRL_AP_MASK 0x001c0000
+#define MPUI_CTRL_AP_MDH 0x00000000
+#define MPUI_CTRL_AP_MHD 0x00040000
+#define MPUI_CTRL_AP_DMH 0x00080000
+#define MPUI_CTRL_AP_HMD 0x000c0000
+#define MPUI_CTRL_AP_DHM 0x00100000
+#define MPUI_CTRL_AP_HDM 0x00140000
+#define MPUI_CTRL_BYTESWAP_MASK 0x00030000
+#define MPUI_CTRL_BYTESWAP_NONE 0x00000000
+#define MPUI_CTRL_BYTESWAP_NONAPI 0x00010000
+#define MPUI_CTRL_BYTESWAP_ALL 0x00020000
+#define MPUI_CTRL_BYTESWAP_API 0x00030000
+#define MPUI_CTRL_TIMEOUT_MASK 0x0000ff00
+#define MPUI_CTRL_APIF_HNSTB_DIV_MASK 0x000000f0
+#define MPUI_CTRL_S_NABORT_GL 0x00000008
+#define MPUI_CTRL_S_NABORT_32BIT 0x00000004
+#define MPUI_CTRL_EN_TIMEOUT 0x00000002
+#define MPUI_CTRL_HF_MCUCLK 0x00000001
+#define DSP_BOOT_CONFIG_DIRECT 0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
+#define DSP_BOOT_CONFIG_IDLE 0x00000002
+#define DSP_BOOT_CONFIG_DL16 0x00000003
+#define DSP_BOOT_CONFIG_DL32 0x00000004
+#define DSP_BOOT_CONFIG_MPUI 0x00000005
+#define DSP_BOOT_CONFIG_INTERNAL 0x00000006
+
+/*
+ * DSP boot mode
+ * direct: 0xffff00
+ * pseudo direct: 0x080000
+ * MPUI: branch 0x010000
+ * internel: branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT 0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
+#define DSP_BOOT_ADR_MPUI 0x010000
+#define DSP_BOOT_ADR_INTERNAL 0x024000
+
+/*
+ * TC
+ */
+#define TC_ENDIANISM_SWAP 0x00000002
+#define TC_ENDIANISM_SWAP_WORD 0x00000002
+#define TC_ENDIANISM_SWAP_BYTE 0x00000000
+#define TC_ENDIANISM_EN 0x00000001
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS 0xffc0
+#define DSPREG_ICR_EMIF 0x0020
+#define DSPREG_ICR_DPLL 0x0010
+#define DSPREG_ICR_PER 0x0008
+#define DSPREG_ICR_CACHE 0x0004
+#define DSPREG_ICR_DMA 0x0002
+#define DSPREG_ICR_CPU 0x0001
+
+#endif /* __OMAP_DSP_OMAP1_DSP_H */
diff --git a/drivers/dsp/dspgateway/omap2_dsp.h b/drivers/dsp/dspgateway/omap2_dsp.h
new file mode 100644
index 0000000..0dc43f0
--- /dev/null
+++ b/drivers/dsp/dspgateway/omap2_dsp.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP2_DSP_H
+#define __OMAP_DSP_OMAP2_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP24XX_DARAM_BASE (DSP_MEM_24XX_VIRT + 0x0)
+#define OMAP24XX_DARAM_SIZE 0x10000
+#define OMAP24XX_SARAM_BASE (DSP_MEM_24XX_VIRT + 0x10000)
+#define OMAP24XX_SARAM_SIZE 0x18000
+#endif
+
+#include <asm/arch/hardware.h>
+
+/*
+ * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX()
+ */
+#ifdef CONFIG_ARCH_OMAP24XX
+#define DSP_IPI_BASE DSP_IPI_24XX_VIRT
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+#define DSP_IPI_BASE DSP_IPI_34XX_VIRT
+#endif
+
+#define DSP_IPI_REVISION (DSP_IPI_BASE + 0x00)
+#define DSP_IPI_SYSCONFIG (DSP_IPI_BASE + 0x10)
+#define DSP_IPI_INDEX (DSP_IPI_BASE + 0x40)
+#define DSP_IPI_ENTRY (DSP_IPI_BASE + 0x44)
+#define DSP_IPI_ENABLE (DSP_IPI_BASE + 0x48)
+#define DSP_IPI_IOMAP (DSP_IPI_BASE + 0x4c)
+#define DSP_IPI_DSPBOOTCONFIG (DSP_IPI_BASE + 0x50)
+
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_MASK 0x00000003
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_8 0x00000000
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_16 0x00000001
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_32 0x00000002
+
+#define DSP_BOOT_CONFIG_DIRECT 0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001
+#define DSP_BOOT_CONFIG_IDLE 0x00000002
+#define DSP_BOOT_CONFIG_DL16 0x00000003
+#define DSP_BOOT_CONFIG_DL32 0x00000004
+#define DSP_BOOT_CONFIG_API 0x00000005
+#define DSP_BOOT_CONFIG_INTERNAL 0x00000006
+
+/*
+ * DSP boot mode
+ * direct: 0xffff00
+ * pseudo direct: 0x080000
+ * API: branch 0x010000
+ * internel: branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT 0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT 0x080000
+#define DSP_BOOT_ADR_API 0x010000
+#define DSP_BOOT_ADR_INTERNAL 0x024000
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS 0xfc00
+#define DSPREG_ICR_HWA 0x0200
+#define DSPREG_ICR_IPORT 0x0100
+#define DSPREG_ICR_MPORT 0x0080
+#define DSPREG_ICR_XPORT 0x0040
+#define DSPREG_ICR_DPORT 0x0020
+#define DSPREG_ICR_DPLL 0x0010
+#define DSPREG_ICR_PER 0x0008
+#define DSPREG_ICR_CACHE 0x0004
+#define DSPREG_ICR_DMA 0x0002
+#define DSPREG_ICR_CPU 0x0001
+
+#endif /* __OMAP_DSP_OMAP2_DSP_H */
diff --git a/drivers/dsp/dspgateway/proclist.h b/drivers/dsp/dspgateway/proclist.h
new file mode 100644
index 0000000..666ca4d
--- /dev/null
+++ b/drivers/dsp/dspgateway/proclist.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_PROCLIST_H
+#define __PLAT_OMAP_DSP_PROCLIST_H
+
+struct proc_list {
+ struct list_head list_head;
+ pid_t pid;
+ struct file *file;
+};
+
+static inline int proc_list_add(spinlock_t *lock, struct list_head *list,
+ struct task_struct *tsk, struct file *file)
+{
+ struct proc_list *new;
+
+ new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+ if (new == NULL)
+ return -ENOMEM;
+ new->pid = tsk->pid;
+ new->file = file;
+ spin_lock(lock);
+ list_add_tail(&new->list_head, list);
+ spin_unlock(lock);
+
+ return 0;
+}
+
+static inline void proc_list_del(spinlock_t *lock, struct list_head *list,
+ struct task_struct *tsk, struct file *file)
+{
+ struct proc_list *pl;
+
+ spin_lock(lock);
+ list_for_each_entry(pl, list, list_head) {
+ if (pl->file == file) {
+ list_del(&pl->list_head);
+ kfree(pl);
+ spin_unlock(lock);
+ return;
+ }
+ }
+
+ /* correspinding file struct isn't found in the list ??? */
+ printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
+ "struct file (%p) not found\n", file);
+ printk(KERN_ERR "listing proc_list...\n");
+ list_for_each_entry(pl, list, list_head)
+ printk(KERN_ERR " pid:%d file:%p\n", pl->pid, pl->file);
+ spin_unlock(lock);
+}
+
+static inline void proc_list_flush(spinlock_t *lock, struct list_head *list)
+{
+ struct proc_list *pl;
+
+ spin_lock(lock);
+ while (!list_empty(list)) {
+ pl = list_entry(list->next, struct proc_list, list_head);
+ list_del(&pl->list_head);
+ kfree(pl);
+ }
+ spin_unlock(lock);
+}
+
+#endif /* __PLAT_OMAP_DSP_PROCLIST_H */
diff --git a/drivers/dsp/dspgateway/task.c b/drivers/dsp/dspgateway/task.c
new file mode 100644
index 0000000..e5ee8e0
--- /dev/null
+++ b/drivers/dsp/dspgateway/task.c
@@ -0,0 +1,3042 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "proclist.h"
+
+/*
+ * devstate: task 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.
+ * FREEZED: task is attached, but reserved to be killed.
+ * ADDFAIL: tadd failed.
+ * ADDING: tadd in process.
+ * DELING: tdel in process.
+ * KILLING: tkill in process.
+ */
+#define TASKDEV_ST_NOTASK 0x00000001
+#define TASKDEV_ST_ATTACHED 0x00000002
+#define TASKDEV_ST_GARBAGE 0x00000004
+#define TASKDEV_ST_INVALID 0x00000008
+#define TASKDEV_ST_ADDREQ 0x00000100
+#define TASKDEV_ST_DELREQ 0x00000200
+#define TASKDEV_ST_FREEZED 0x00000400
+#define TASKDEV_ST_ADDFAIL 0x00001000
+#define TASKDEV_ST_ADDING 0x00010000
+#define TASKDEV_ST_DELING 0x00020000
+#define TASKDEV_ST_KILLING 0x00040000
+#define TASKDEV_ST_STATE_MASK 0x7fffffff
+#define TASKDEV_ST_STALE 0x80000000
+
+static struct {
+ long state;
+ char *name;
+} devstate_desc[] = {
+ { TASKDEV_ST_NOTASK, "notask" },
+ { TASKDEV_ST_ATTACHED, "attached" },
+ { TASKDEV_ST_GARBAGE, "garbage" },
+ { TASKDEV_ST_INVALID, "invalid" },
+ { TASKDEV_ST_ADDREQ, "addreq" },
+ { TASKDEV_ST_DELREQ, "delreq" },
+ { TASKDEV_ST_FREEZED, "freezed" },
+ { TASKDEV_ST_ADDFAIL, "addfail" },
+ { TASKDEV_ST_ADDING, "adding" },
+ { TASKDEV_ST_DELING, "deling" },
+ { TASKDEV_ST_KILLING, "killing" },
+};
+
+static char *devstate_name(long state)
+{
+ int i;
+ int max = ARRAY_SIZE(devstate_desc);
+
+ for (i = 0; i < max; i++) {
+ if (state & devstate_desc[i].state)
+ return devstate_desc[i].name;
+ }
+ return "unknown";
+}
+
+struct rcvdt_bk_struct {
+ struct ipblink link;
+ unsigned int rp;
+};
+
+struct taskdev {
+ struct bus_type *bus;
+ struct device dev; /* Generic device interface */
+
+ long state;
+ struct rw_semaphore state_sem;
+ wait_queue_head_t state_wait_q;
+ struct mutex usecount_lock;
+ unsigned int usecount;
+ char name[TNM_LEN];
+ struct file_operations fops;
+ spinlock_t proc_list_lock;
+ struct list_head proc_list;
+ struct dsptask *task;
+
+ /* read stuff */
+ wait_queue_head_t read_wait_q;
+ struct mutex read_mutex;
+ spinlock_t read_lock;
+ union {
+ struct kfifo *fifo; /* for active word */
+ struct rcvdt_bk_struct bk;
+ } rcvdt;
+
+ /* write stuff */
+ wait_queue_head_t write_wait_q;
+ struct mutex write_mutex;
+ spinlock_t wsz_lock;
+ size_t wsz;
+
+ /* tctl stuff */
+ wait_queue_head_t tctl_wait_q;
+ struct mutex tctl_mutex;
+ int tctl_stat;
+ int tctl_ret; /* return value for tctl_show() */
+
+ /* device lock */
+ struct mutex lock;
+ pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+ enum {
+ TASK_ST_ERR = 0,
+ TASK_ST_READY,
+ TASK_ST_CFGREQ
+ } state;
+ u8 tid;
+ char name[TNM_LEN];
+ u16 ttyp;
+ struct taskdev *dev;
+
+ /* read stuff */
+ struct ipbuf_p *ipbuf_pvt_r;
+
+ /* write stuff */
+ struct ipbuf_p *ipbuf_pvt_w;
+
+ /* mmap stuff */
+ void *map_base;
+ size_t map_length;
+};
+
+#define sndtyp_acv(ttyp) ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp) (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp) ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp) (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp) ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp) (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp) ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp) (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp) ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp) (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp) ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp) (!((ttyp) & TTYP_PVMD))
+
+static inline int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+ .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task; /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid) ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+ devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev) up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+ devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev) up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+static struct device_attribute dev_attr_devname = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap = __ATTR_RO(mmap);
+
+static inline void set_taskdev_state(struct taskdev *dev, int state)
+{
+ pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
+ dev->name,
+ (dev->task ? dev->task->tid : -1),
+ devstate_name(dev->state),
+ devstate_name(state));
+ dev->state = state;
+}
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw) \
+static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate, \
+ int timeout) \
+{ \
+ DEFINE_WAIT(wait); \
+ down_##rw(&dev->state_sem); \
+ while (!(dev->state & devstate)) { \
+ up_##rw(&dev->state_sem); \
+ prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
+ if (!timeout) \
+ timeout = MAX_SCHEDULE_TIMEOUT; \
+ timeout = schedule_timeout(timeout); \
+ finish_wait(&dev->state_wait_q, &wait); \
+ if (timeout == 0) \
+ return -ETIME; \
+ if (signal_pending(current)) \
+ return -EINTR; \
+ down_##rw(&dev->state_sem); \
+ } \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_TIMEOUT(read)
+BUILD_DEVSTATE_LOCK_TIMEOUT(write)
+
+#define BUILD_DEVSTATE_LOCK_AND_TEST(rw) \
+static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate) \
+{ \
+ down_##rw(&dev->state_sem); \
+ if (dev->state & devstate) \
+ return 1; /* success */ \
+ /* failure */ \
+ up_##rw(&dev->state_sem); \
+ return 0; \
+}
+BUILD_DEVSTATE_LOCK_AND_TEST(read)
+BUILD_DEVSTATE_LOCK_AND_TEST(write)
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (has_taskdev_lock(dev))
+ ret = mutex_lock_interruptible(lock);
+ else {
+ if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+ return ret;
+ ret = mutex_lock_interruptible(lock);
+ mutex_unlock(&dev->lock);
+ }
+
+ return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+ struct mutex *lock)
+{
+ int ret;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+ devstate_read_unlock(dev);
+
+ return ret;
+}
+
+static inline void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+ struct mutex *lock)
+{
+ mutex_unlock(lock);
+ devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ if (sndtyp_wd(ttyp)) {
+ /* word receiving */
+ kfifo_reset(dev->rcvdt.fifo);
+ } else {
+ /* block receiving */
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+ if (sndtyp_gbl(ttyp))
+ ipblink_flush(&rcvdt->link);
+ else {
+ ipblink_flush_pvt(&rcvdt->link);
+ release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
+ printk(KERN_ERR
+ "omapdsp: buffer size can be changed only for "
+ "active word sending task.\n");
+ return -EINVAL;
+ }
+ if ((sz == 0) || (sz & 1)) {
+ printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
+ "it must be even and non-zero value.\n", sz);
+ return -EINVAL;
+ }
+
+ if (kfifo_len(dev->rcvdt.fifo)) {
+ printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+ return -EIO;
+ }
+
+ kfifo_free(dev->rcvdt.fifo);
+ dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to change receive buffer size. "
+ "(%ld bytes for %s)\n", sz, dev->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static inline int has_taskdev_lock(struct taskdev *dev)
+{
+ return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+ if (mutex_lock_interruptible(&dev->lock))
+ return -EINTR;
+ dev->lock_pid = current->pid;
+ return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+ if (!has_taskdev_lock(dev)) {
+ printk(KERN_ERR
+ "omapdsp: an illegal process attempted to "
+ "unlock the dsptask lock!\n");
+ return -EINVAL;
+ }
+ dev->lock_pid = 0;
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+ u16 ttyp;
+ int ret;
+
+ task->tid = tid;
+ dsptask[tid] = task;
+
+ /* TCFG request */
+ task->state = TASK_ST_CFGREQ;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_cmd = MBOX_CMD_DSP_TCFG;
+ mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (task->state != TASK_ST_READY) {
+ printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ if (strlen(task->name) <= 1)
+ sprintf(task->name, "%d", tid);
+ pr_info("omapdsp: task %d: name %s\n", tid, task->name);
+
+ ttyp = task->ttyp;
+
+ /*
+ * task info sanity check
+ */
+
+ /* task type check */
+ if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+ 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) &&
+ (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ 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) &&
+ ((!ALIGN((unsigned long)task->map_base, PAGE_SIZE)) ||
+ (!ALIGN(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;
+ }
+
+ return 0;
+
+fail_out:
+ dsptask[tid] = NULL;
+ return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+ mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+ int i, ret;
+ struct taskdev *devheap;
+ struct dsptask *taskheap;
+ size_t devheapsz, taskheapsz;
+
+ pr_info("omapdsp: found %d task(s)\n", n);
+ if (n == 0)
+ return 0;
+
+ /*
+ * reducing kmalloc!
+ */
+ devheapsz = sizeof(struct taskdev) * n;
+ taskheapsz = sizeof(struct dsptask) * n;
+ heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+ if (heap == NULL)
+ return -ENOMEM;
+ devheap = heap;
+ taskheap = heap + devheapsz;
+
+ n_task = n;
+ for (i = 0; i < n; i++) {
+ struct taskdev *dev = &devheap[i];
+ struct dsptask *task = &taskheap[i];
+
+ if ((ret = dsp_task_config(task, i)) < 0)
+ return ret;
+ if ((ret = taskdev_init(dev, task->name, i)) < 0)
+ return ret;
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ return ret;
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ }
+
+ return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+ dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+ unsigned char minor;
+ u8 tid;
+ struct dsptask *task;
+
+ for (minor = 0; minor < n_task; minor++) {
+ /*
+ * taskdev[minor] can be NULL in case of
+ * configuration failure
+ */
+ if (taskdev[minor])
+ taskdev_delete(minor);
+ }
+ for (; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor])
+ dsp_rmdev_minor(minor);
+ }
+
+ for (tid = 0; tid < n_task; tid++) {
+ /*
+ * dsptask[tid] can be NULL in case of
+ * configuration failure
+ */
+ task = dsptask[tid];
+ if (task)
+ dsp_task_unconfig(task);
+ }
+ for (; tid < TASKDEV_MAX; tid++) {
+ task = dsptask[tid];
+ if (task) {
+ /*
+ * on-demand tasks should be deleted in
+ * rmdev_minor(), but just in case.
+ */
+ dsp_task_unconfig(task);
+ kfree(task);
+ }
+ }
+
+ if (heap) {
+ kfree(heap);
+ heap = NULL;
+ }
+
+ n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+ .name = "dsptask",
+ .bus = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+ return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+ struct taskdev *dev;
+ unsigned char minor;
+ unsigned int usecount;
+
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ dev = taskdev[minor];
+ if (dev == NULL)
+ continue;
+ if ((usecount = dev->usecount) > 0) {
+ printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+ dev->name, usecount);
+ return 1;
+ }
+/*
+ if ((dev->state & (TASKDEV_ST_ADDREQ |
+ TASKDEV_ST_DELREQ)) {
+*/
+ if (dev->state & TASKDEV_ST_ADDREQ) {
+ printk("dsp_taskmod_busy(): %s is in %s\n",
+ dev->name, devstate_name(dev->state));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (kfifo_len(dev->rcvdt.fifo) == 0)
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ ssize_t ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (ipblink_empty(&rcvdt->link))
+ schedule();
+ finish_wait(&dev->read_wait_q, &wait);
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /* copy from delayed IPBUF */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ if (!ipblink_empty(&rcvdt->link)) {
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ unsigned char *base, *src;
+ size_t bkcnt;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ 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 = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(base) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ src = base + rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = count;
+ rcvdt->rp += count;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ret = bkcnt;
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ rcvdt->rp = 0;
+ }
+ pv_out2:
+ dsp_mem_disable(src);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ }
+ } else {
+ /* global */
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ while (!ipblink_empty(&rcvdt->link)) {
+ unsigned char *src;
+ size_t bkcnt;
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+ src = ipb_h->p->d + rcvdt->rp;
+ bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+ if (bkcnt > count) {
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += count;
+ rcvdt->rp += count;
+ break;
+ } else {
+ if (copy_to_user_dsp(buf, src, bkcnt)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ret += bkcnt;
+ buf += bkcnt;
+ count -= bkcnt;
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ rcvdt->rp = 0;
+ }
+ }
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+ if (kfifo_len(dev->rcvdt.fifo) == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+ int ret = 0;
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_read().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+
+ mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+ &dev->read_wait_q);
+
+ if (ipblink_empty(&rcvdt->link)) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ /*
+ * We will not receive more than requested count.
+ */
+ if (sndtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+ size_t rcvcnt;
+ void *src;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ 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 = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(src) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, src, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipblink_del_pvt(&rcvdt->link);
+ release_ipbuf_pvt(ipbp);
+ ret = count;
+pv_out2:
+ dsp_mem_disable(src);
+pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+ size_t rcvcnt;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+ if (count > rcvcnt)
+ count = rcvcnt;
+ if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipblink_del_top(&rcvdt->link);
+ unuse_ipbuf(ipb_h);
+ ret = count;
+gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ u16 wd;
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else {
+ /* force! */
+ count = 2;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (copy_from_user(&wd, buf, count)) {
+ ret = -EFAULT;
+ goto up_out;
+ }
+
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+ spin_unlock(&dev->wsz_lock);
+ goto up_out;
+ }
+ ret = count;
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ spin_unlock(&dev->wsz_lock);
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (count == 0) {
+ return 0;
+ } else if (count & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: odd count is illegal for DSP task device.\n");
+ return -EINVAL;
+ } else if ((int)buf & 0x1) {
+ printk(KERN_ERR
+ "omapdsp: buf should be word aligned for "
+ "dsp_task_write().\n");
+ return -EINVAL;
+ }
+
+ if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+ return -ENODEV;
+
+ prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (dev->wsz == 0)
+ schedule();
+ finish_wait(&dev->write_wait_q, &wait);
+ if (dev->wsz == 0) {
+ /* failure */
+ if (signal_pending(current))
+ ret = -EINTR;
+ goto up_out;
+ }
+
+ if (count > dev->wsz)
+ count = dev->wsz;
+
+ if (rcvtyp_pvt(dev->task->ttyp)) {
+ /* private */
+ struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+ unsigned char *dst;
+
+ if (dsp_mem_enable(ipbp) < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ dst = MKVIRT(ipbp->ah, ipbp->al);
+ if (dsp_address_validate(dst, count, "task %s write buffer",
+ dev->task->name) < 0) {
+ ret = -EINVAL;
+ goto pv_out1;
+ }
+ if (dsp_mem_enable(dst) < 0) {
+ ret = -EBUSY;
+ goto pv_out1;
+ }
+ if (copy_from_user_dsp(dst, buf, count)) {
+ ret = -EFAULT;
+ goto pv_out2;
+ }
+ ipbp->c = count/2;
+ ipbp->s = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ }
+ spin_unlock(&dev->wsz_lock);
+ pv_out2:
+ dsp_mem_disable(dst);
+ pv_out1:
+ dsp_mem_disable(ipbp);
+ } else {
+ /* global */
+ struct ipbuf_head *ipb_h;
+
+ if (dsp_mem_enable_ipbuf() < 0) {
+ ret = -EBUSY;
+ goto up_out;
+ }
+ if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+ goto gb_out;
+ if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+ release_ipbuf(ipb_h);
+ ret = -EFAULT;
+ goto gb_out;
+ }
+ ipb_h->p->c = count/2;
+ ipb_h->p->sa = dev->task->tid;
+ spin_lock(&dev->wsz_lock);
+ if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+ if (rcvtyp_acv(dev->task->ttyp))
+ dev->wsz = 0;
+ ret = count;
+ ipb_bsycnt_inc(&ipbcfg);
+ } else
+ release_ipbuf(ipb_h);
+ spin_unlock(&dev->wsz_lock);
+ gb_out:
+ dsp_mem_disable_ipbuf();
+ }
+
+ up_out:
+ taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+ return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task = dev->task;
+ unsigned int mask = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return 0;
+ poll_wait(file, &dev->read_wait_q, wait);
+ poll_wait(file, &dev->write_wait_q, wait);
+ if (sndtyp_psv(task->ttyp) ||
+ (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
+ (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+ mask |= POLLIN | POLLRDNORM;
+ if (dev->wsz)
+ mask |= POLLOUT | POLLWRNORM;
+ devstate_read_unlock(dev);
+
+ return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+ int tctl_argc;
+ struct mb_exarg mbarg, *mbargp;
+ int interactive;
+ u8 tid;
+ int ret = 0;
+
+ if (cmd < 0x8000) {
+ /*
+ * 0x0000 - 0x7fff
+ * system reserved TCTL commands
+ */
+ switch (cmd) {
+ case TCTL_TEN:
+ case TCTL_TDIS:
+ tctl_argc = 0;
+ interactive = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /*
+ * 0x8000 - 0xffff
+ * user-defined TCTL commands
+ */
+ else if (cmd < 0x8100) {
+ /* 0x8000-0x80ff: no arg, non-interactive */
+ tctl_argc = 0;
+ interactive = 0;
+ } else if (cmd < 0x8200) {
+ /* 0x8100-0x81ff: 1 arg, non-interactive */
+ tctl_argc = 1;
+ interactive = 0;
+ } else if (cmd < 0x9000) {
+ /* 0x8200-0x8fff: reserved */
+ return -EINVAL;
+ } else if (cmd < 0x9100) {
+ /* 0x9000-0x90ff: no arg, interactive */
+ tctl_argc = 0;
+ interactive = 1;
+ } else if (cmd < 0x9200) {
+ /* 0x9100-0x91ff: 1 arg, interactive */
+ tctl_argc = 1;
+ interactive = 1;
+ } else {
+ /* 0x9200-0xffff: reserved */
+ return -EINVAL;
+ }
+
+ /*
+ * if argc < 0, use tctl_argc as is.
+ * if argc >= 0, check arg count.
+ */
+ if ((argc >= 0) && (argc != tctl_argc))
+ return -EINVAL;
+
+ /*
+ * issue TCTL
+ */
+ if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+ return -EINTR;
+
+ tid = dev->task->tid;
+ if (tctl_argc > 0) {
+ mbarg.argc = tctl_argc;
+ mbarg.tid = tid;
+ mbarg.argv = argv;
+ mbargp = &mbarg;
+ } else
+ mbargp = NULL;
+
+ if (interactive) {
+ dev->tctl_stat = -EINVAL;
+
+ mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+ &dev->tctl_wait_q);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto up_out;
+ }
+ if ((ret = dev->tctl_stat) < 0) {
+ printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+ goto up_out;
+ }
+ } else
+ mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+ mutex_unlock(&dev->tctl_mutex);
+ return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ int ret;
+
+ if (cmd < 0x10000) {
+ /* issue TCTL */
+ u16 mbargv[1];
+
+ mbargv[0] = arg & 0xffff;
+ return dsp_tctl_issue(dev, cmd, -1, mbargv);
+ }
+
+ /* non TCTL ioctls */
+ switch (cmd) {
+
+ case TASK_IOCTL_LOCK:
+ ret = taskdev_lock(dev);
+ break;
+
+ case TASK_IOCTL_UNLOCK:
+ ret = taskdev_unlock(dev);
+ break;
+
+ case TASK_IOCTL_BFLSH:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_flush_buf(dev);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_SETBSZ:
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, arg);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+ break;
+
+ case TASK_IOCTL_GETNAME:
+ ret = 0;
+ if (copy_to_user((void __user *)arg, dev->name,
+ strlen(dev->name) + 1))
+ ret = -EFAULT;
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+
+ }
+
+ 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 & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_use(&dsp_mmu, 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 & TASKDEV_ST_ATTACHED));
+ task = dev->task;
+ omap_mmu_exmap_unuse(&dsp_mmu, 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_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return NOPAGE_SIGBUS;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+ .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)
+{
+ void *tmp_vadr;
+ unsigned long tmp_padr, tmp_vmadr, off;
+ size_t req_len, tmp_len;
+ unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+ struct dsptask *task;
+ int ret = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+ task = dev->task;
+
+ /*
+ * Don't swap this area out
+ * Don't dump this area to a core file
+ */
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+
+ /* Do not cache this area */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ req_len = vma->vm_end - vma->vm_start;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ tmp_vmadr = vma->vm_start;
+ tmp_vadr = task->map_base + off;
+ do {
+ tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len);
+ if (tmp_padr == 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: illegal address "
+ "for mmap: %p", task->name, tmp_vadr);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ if (tmp_len > req_len)
+ tmp_len = req_len;
+
+ pr_debug("omapdsp: mmap info: "
+ "vmadr = %08lx, padr = %08lx, len = %x\n",
+ tmp_vmadr, tmp_padr, tmp_len);
+ if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+ tmp_len, vma->vm_page_prot) != 0) {
+ printk(KERN_ERR
+ "omapdsp: task %s: remap_page_range() failed.\n",
+ task->name);
+ /* partial mapping will be cleared in upper layer */
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ req_len -= tmp_len;
+ tmp_vmadr += tmp_len;
+ tmp_vadr += tmp_len;
+ } while (req_len);
+
+ vma->vm_ops = &dsp_task_vm_ops;
+ vma->vm_private_data = dev;
+ omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+ devstate_read_unlock(dev);
+ return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev;
+ int ret = 0;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+ return -ENODEV;
+
+ restart:
+ mutex_lock(&dev->usecount_lock);
+ down_write(&dev->state_sem);
+
+ /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+ case TASKDEV_ST_NOTASK:
+ break;
+ case TASKDEV_ST_ATTACHED:
+ goto attached;
+
+ case TASKDEV_ST_INVALID:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return -ENODEV;
+
+ case TASKDEV_ST_FREEZED:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_DELREQ:
+ /* on the kill process. wait until it becomes NOTASK. */
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+ return -EINTR;
+ devstate_write_unlock(dev);
+ goto restart;
+ }
+
+ /* NOTASK */
+ set_taskdev_state(dev, TASKDEV_ST_ADDREQ);
+ /* wake up twch daemon for tadd */
+ dsp_twch_touch();
+ up_write(&dev->state_sem);
+ if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_ADDFAIL) < 0) {
+ /* cancelled */
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ mutex_unlock(&dev->usecount_lock);
+ /* out of control ??? */
+ return -EINTR;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ ret = -EINTR;
+ goto change_out;
+ }
+ if (dev->state & TASKDEV_ST_ADDFAIL) {
+ printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+ dev->name);
+ ret = -EBUSY;
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ goto change_out;
+ }
+
+ attached:
+ ret = proc_list_add(&dev->proc_list_lock,
+ &dev->proc_list, current, file);
+ if (ret)
+ goto out;
+
+ dev->usecount++;
+ file->f_op = &dev->fops;
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_map_update(current);
+ dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+ return 0;
+
+ change_out:
+ wake_up_interruptible_all(&dev->state_wait_q);
+ out:
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE /* not used currently. */
+ dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+ if (has_taskdev_lock(dev))
+ taskdev_unlock(dev);
+
+ proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+ mutex_lock(&dev->usecount_lock);
+ if (--dev->usecount > 0) {
+ /* other processes are using this device. no state change. */
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+ }
+
+ /* usecount == 0 */
+ down_write(&dev->state_sem);
+
+ /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_KILLING:
+ break;
+
+ case TASKDEV_ST_GARBAGE:
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ if (is_dynamic_task(minor)) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ /* wake up twch daemon for tdel */
+ dsp_twch_touch();
+ }
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+ mutex_unlock(&dev->usecount_lock);
+ return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+ struct taskdev *dev;
+ int status;
+ unsigned char minor;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* naming check */
+ for (minor = 0; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device name %s is already "
+ "in use.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ /* find free minor number */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] == NULL)
+ goto do_make;
+ }
+ printk(KERN_ERR "omapdsp: Too many task devices.\n");
+ ret = -EBUSY;
+ goto out;
+
+do_make:
+ if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((status = taskdev_init(dev, name, minor)) < 0) {
+ kfree(dev);
+ ret = status;
+ goto out;
+ }
+ ret = minor;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+ unsigned char minor;
+ int status;
+ int ret;
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ /* find in dynamic devices */
+ for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+ goto do_remove;
+ }
+
+ /* find in static devices */
+ for (minor = 0; minor < n_task; minor++) {
+ if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+ printk(KERN_ERR
+ "omapdsp: task device %s is static.\n", name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+ return -EINVAL;
+
+do_remove:
+ ret = minor;
+ if ((status = dsp_rmdev_minor(minor)) < 0)
+ ret = status;
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ while (!down_write_trylock(&dev->state_sem)) {
+ down_read(&dev->state_sem);
+ if (dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED)) {
+ /*
+ * task is working. kill it.
+ * ATTACHED -> FREEZED can be changed under
+ * down_read of state_sem..
+ */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ }
+ up_read(&dev->state_sem);
+ schedule();
+ }
+
+ switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+ case TASKDEV_ST_NOTASK:
+ case TASKDEV_ST_INVALID:
+ /* fine */
+ goto notask;
+
+ case TASKDEV_ST_ATTACHED:
+ case TASKDEV_ST_FREEZED:
+ /* task is working. kill it. */
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ up_write(&dev->state_sem);
+ dsp_tdel_bh(dev, TDEL_KILL);
+ goto invalidate;
+
+ case TASKDEV_ST_ADDREQ:
+ /* open() is waiting. drain it. */
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_DELREQ:
+ /* nobody is waiting. */
+ set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ break;
+
+ case TASKDEV_ST_ADDING:
+ case TASKDEV_ST_DELING:
+ case TASKDEV_ST_KILLING:
+ case TASKDEV_ST_GARBAGE:
+ case TASKDEV_ST_ADDFAIL:
+ /* transient state. wait for a moment. */
+ break;
+
+ }
+
+ up_write(&dev->state_sem);
+
+invalidate:
+ /* wait for some time and hope the state is settled */
+ devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+ if (!(dev->state & TASKDEV_ST_NOTASK)) {
+ printk(KERN_WARNING
+ "omapdsp: illegal device state (%s) on rmdev %s.\n",
+ devstate_name(dev->state), dev->name);
+ }
+notask:
+ set_taskdev_state(dev, TASKDEV_ST_INVALID);
+ devstate_read_unlock(dev);
+
+ taskdev_delete(minor);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct file_operations dsp_task_fops = {
+ .owner = THIS_MODULE,
+ .poll = dsp_task_poll,
+ .ioctl = dsp_task_ioctl,
+ .open = dsp_task_open,
+ .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+ int ret;
+ struct device *task_dev;
+
+ taskdev[minor] = dev;
+
+ spin_lock_init(&dev->proc_list_lock);
+ INIT_LIST_HEAD(&dev->proc_list);
+ init_waitqueue_head(&dev->read_wait_q);
+ init_waitqueue_head(&dev->write_wait_q);
+ init_waitqueue_head(&dev->tctl_wait_q);
+ mutex_init(&dev->read_mutex);
+ mutex_init(&dev->write_mutex);
+ mutex_init(&dev->tctl_mutex);
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->wsz_lock);
+ dev->tctl_ret = -EINVAL;
+ dev->lock_pid = 0;
+
+ strncpy(dev->name, name, TNM_LEN);
+ dev->name[TNM_LEN-1] = '\0';
+ set_taskdev_state(dev, (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK);
+ dev->usecount = 0;
+ mutex_init(&dev->usecount_lock);
+ memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+ dev->dev.parent = omap_dsp->dev;
+ dev->dev.bus = &dsptask_bus;
+ sprintf(dev->dev.bus_id, "dsptask%d", minor);
+ dev->dev.release = dsptask_dev_release;
+ ret = device_register(&dev->dev);
+ if (ret) {
+ printk(KERN_ERR "device_register failed: %d\n", ret);
+ return ret;
+ }
+ ret = device_create_file(&dev->dev, &dev_attr_devname);
+ if (ret)
+ goto fail_create_devname;
+ ret = device_create_file(&dev->dev, &dev_attr_devstate);
+ if (ret)
+ goto fail_create_devstate;
+ ret = device_create_file(&dev->dev, &dev_attr_proc_list);
+ if (ret)
+ goto fail_create_proclist;
+
+ task_dev = device_create(dsp_task_class, NULL,
+ MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+ "dsptask%d", (int)minor);
+
+ if (unlikely(IS_ERR(task_dev))) {
+ ret = -EINVAL;
+ goto fail_create_taskclass;
+ }
+
+ init_waitqueue_head(&dev->state_wait_q);
+ init_rwsem(&dev->state_sem);
+
+ return 0;
+
+ fail_create_taskclass:
+ device_remove_file(&dev->dev, &dev_attr_proc_list);
+ fail_create_proclist:
+ device_remove_file(&dev->dev, &dev_attr_devstate);
+ fail_create_devstate:
+ device_remove_file(&dev->dev, &dev_attr_devname);
+ fail_create_devname:
+ device_unregister(&dev->dev);
+ return ret;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+ struct taskdev *dev = taskdev[minor];
+
+ if (!dev)
+ return;
+ 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);
+ device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+ device_unregister(&dev->dev);
+ proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+ taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+ u16 ttyp = task->ttyp;
+ int ret;
+
+ dev->fops.read =
+ sndtyp_acv(ttyp) ?
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+ /* sndtyp_bk */ dsp_task_read_bk_acv:
+ /* sndtyp_psv */
+ sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+ /* sndtyp_bk */ dsp_task_read_bk_psv;
+ if (sndtyp_wd(ttyp)) {
+ /* word */
+ size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
+
+ dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
+ &dev->read_lock);
+ if (IS_ERR(dev->rcvdt.fifo)) {
+ printk(KERN_ERR
+ "omapdsp: unable to allocate receive buffer. "
+ "(%d bytes for %s)\n", fifosz, dev->name);
+ return -ENOMEM;
+ }
+ } else {
+ /* block */
+ INIT_IPBLINK(&dev->rcvdt.bk.link);
+ dev->rcvdt.bk.rp = 0;
+ }
+
+ dev->fops.write =
+ rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+ /* rcvbyp_bk */ dsp_task_write_bk;
+ dev->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */
+ rcvtyp_wd(ttyp) ? 2 : /* passive word */
+ ipbcfg.lsz*2; /* passive block */
+
+ if (task->map_length)
+ dev->fops.mmap = dsp_task_mmap;
+
+ ret = device_create_file(&dev->dev, &dev_attr_taskname);
+ if (unlikely(ret))
+ goto fail_create_taskname;
+ ret = device_create_file(&dev->dev, &dev_attr_ttyp);
+ if (unlikely(ret))
+ goto fail_create_ttyp;
+ ret = device_create_file(&dev->dev, &dev_attr_wsz);
+ if (unlikely(ret))
+ goto fail_create_wsz;
+ if (task->map_length) {
+ ret = device_create_file(&dev->dev, &dev_attr_mmap);
+ if (unlikely(ret))
+ goto fail_create_mmap;
+ }
+ if (sndtyp_wd(ttyp)) {
+ ret = device_create_file(&dev->dev, &dev_attr_fifosz);
+ if (unlikely(ret))
+ goto fail_create_fifosz;
+ ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
+ if (unlikely(ret))
+ goto fail_create_fifocnt;
+ } else {
+ ret = device_create_file(&dev->dev, &dev_attr_ipblink);
+ if (unlikely(ret))
+ goto fail_create_ipblink;
+ }
+
+ dev->task = task;
+ task->dev = dev;
+
+ return 0;
+
+ fail_create_fifocnt:
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ fail_create_ipblink:
+ fail_create_fifosz:
+ if (task->map_length)
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ fail_create_mmap:
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ fail_create_wsz:
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ fail_create_ttyp:
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ fail_create_taskname:
+ if (task->map_length)
+ dev->fops.mmap = NULL;
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->task = NULL;
+
+ return ret;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+ u16 ttyp = dev->task->ttyp;
+
+ device_remove_file(&dev->dev, &dev_attr_taskname);
+ device_remove_file(&dev->dev, &dev_attr_ttyp);
+ if (sndtyp_wd(ttyp)) {
+ device_remove_file(&dev->dev, &dev_attr_fifosz);
+ device_remove_file(&dev->dev, &dev_attr_fifocnt);
+ } else
+ device_remove_file(&dev->dev, &dev_attr_ipblink);
+ device_remove_file(&dev->dev, &dev_attr_wsz);
+ if (dev->task->map_length) {
+ device_remove_file(&dev->dev, &dev_attr_mmap);
+ dev->fops.mmap = NULL;
+ }
+
+ dev->fops.read = NULL;
+ taskdev_flush_buf(dev);
+ if (sndtyp_wd(ttyp))
+ kfifo_free(dev->rcvdt.fifo);
+
+ dev->fops.write = NULL;
+ dev->wsz = 0;
+
+ pr_info("omapdsp: taskdev %s disabled.\n", dev->name);
+ dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+ struct dsptask *task;
+ struct mb_exarg arg;
+ u8 tid, tid_response;
+ u16 argv[2];
+ int ret = 0;
+
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tadd. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_ADDING);
+ devstate_write_unlock(dev);
+
+ if (adr == TADD_ABORTADR) {
+ /* aborting tadd intentionally */
+ pr_info("omapdsp: tadd address is ABORTADR.\n");
+ goto fail_out;
+ }
+ if (adr >= DSPSPACE_SIZE) {
+ printk(KERN_ERR
+ "omapdsp: illegal address 0x%08x for tadd\n", adr);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+
+ adr >>= 1; /* word address */
+ argv[0] = adr >> 16; /* addrh */
+ argv[1] = adr & 0xffff; /* addrl */
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ ret = -EINTR;
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TADD;
+ arg.tid = TID_ANON;
+ arg.argc = 2;
+ arg.argv = argv;
+
+ if (dsp_mem_sync_inc() < 0) {
+ printk(KERN_ERR "omapdsp: memory sync failed!\n");
+ ret = -EBUSY;
+ goto fail_out;
+ }
+ mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+ tid = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid == TID_ANON) {
+ printk(KERN_ERR "omapdsp: tadd failed!\n");
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((tid < n_task) || dsptask[tid]) {
+ printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+ ret = -EINVAL;
+ goto fail_out;
+ }
+ if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto del_out;
+ }
+
+ if ((ret = dsp_task_config(task, tid)) < 0)
+ goto free_out;
+
+ if (strcmp(dev->name, task->name)) {
+ printk(KERN_ERR
+ "omapdsp: task name (%s) doesn't match with "
+ "device name (%s).\n", task->name, dev->name);
+ ret = -EINVAL;
+ goto free_out;
+ }
+
+ if ((ret = taskdev_attach_task(dev, task)) < 0)
+ goto free_out;
+
+ dsp_task_init(task);
+ pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+ set_taskdev_state(dev, TASKDEV_ST_ATTACHED);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return 0;
+
+free_out:
+ kfree(task);
+
+del_out:
+ printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ printk(KERN_ERR "omapdsp: aborting tdel process. "
+ "DSP side could be corrupted.\n");
+ goto fail_out;
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+ if (tid_response != tid)
+ printk(KERN_ERR "omapdsp: tdel failed. "
+ "DSP side could be corrupted.\n");
+
+fail_out:
+ set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = minor;
+ if ((status = dsp_tadd(dev, adr)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+ if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+ printk(KERN_ERR
+ "omapdsp: taskdev %s is not requesting for tdel. "
+ "(state is %s)\n", dev->name, devstate_name(dev->state));
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_DELING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tdel(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+ while (!down_write_trylock(&dev->state_sem)) {
+ if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for "
+ "taskdev %s\n", dev->name);
+ return -EINVAL;
+ }
+ /* ATTACHED -> FREEZED can be changed under read semaphore. */
+ set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+ devstate_read_unlock(dev);
+ schedule();
+ }
+
+ if (!(dev->state & (TASKDEV_ST_ATTACHED |
+ TASKDEV_ST_FREEZED))) {
+ printk(KERN_ERR
+ "omapdsp: task has not been attached for taskdev %s\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ if (!is_dynamic_task(dev->task->tid)) {
+ printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+ dev->name);
+ devstate_write_unlock(dev);
+ return -EINVAL;
+ }
+ set_taskdev_state(dev, TASKDEV_ST_KILLING);
+ devstate_write_unlock(dev);
+
+ return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+ struct taskdev *dev;
+ int status;
+ int ret;
+
+ if (mutex_lock_interruptible(&devmgr_lock))
+ return -EINTR;
+
+ if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+ printk(KERN_ERR
+ "omapdsp: no task device with minor %d\n", minor);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = minor;
+ if ((status = dsp_tkill(dev)) < 0)
+ ret = status;
+
+out:
+ mutex_unlock(&devmgr_lock);
+ return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+ struct dsptask *task;
+ u8 tid, tid_response;
+ int ret = 0;
+
+ task = dev->task;
+ tid = task->tid;
+ if (mutex_lock_interruptible(&cfg_lock)) {
+ if (type == TDEL_SAFE) {
+ set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+ return -EINTR;
+ } else {
+ tid_response = TID_ANON;
+ ret = -EINTR;
+ goto detach_out;
+ }
+ }
+ cfg_tid = TID_ANON;
+ cfg_cmd = MBOX_CMD_DSP_TDEL;
+ mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+ tid_response = cfg_tid;
+ cfg_tid = TID_ANON;
+ cfg_cmd = 0;
+ mutex_unlock(&cfg_lock);
+
+detach_out:
+ taskdev_detach_task(dev);
+ dsp_task_unconfig(task);
+ kfree(task);
+
+ if (tid_response != tid) {
+ printk(KERN_ERR "omapdsp: %s failed!\n",
+ (type == TDEL_SAFE) ? "tdel" : "tkill");
+ ret = -EINVAL;
+ }
+ down_write(&dev->state_sem);
+ set_taskdev_state(dev, (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+ TASKDEV_ST_NOTASK);
+ wake_up_interruptible_all(&dev->state_wait_q);
+ up_write(&dev->state_sem);
+
+ return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+ if (taskdev[minor]) {
+ long state = taskdev[minor]->state;
+ taskdev[minor]->state |= TASKDEV_ST_STALE;
+ return state;
+ } else
+ return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+ unsigned int n;
+ u8 tid = mb->cmd_l;
+ u16 data = mb->data;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_bk(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDSND from block sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_psv(task->ttyp) &&
+ !waitqueue_active(&task->dev->read_wait_q)) {
+ printk(KERN_WARNING
+ "mbox: WDSND from passive sending task (task%d) "
+ "without request!\n", tid);
+ return;
+ }
+
+ n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
+ sizeof(data));
+ if (n != sizeof(data))
+ printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
+
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: WDREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = 2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 bid = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_head *ipb_h;
+ u16 cnt;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+ ipb_bsycnt_dec(&ipbcfg);
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from word sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sndtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSND from private sending task! (task%d)\n", tid);
+ goto unuse_ipbuf_out;
+ }
+ if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+ return;
+ }
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ cnt = ipb_h->p->c;
+ if (cnt > ipbcfg.lsz) {
+ printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+ cnt, ipbcfg.lsz);
+ goto unuse_ipbuf_out;
+ }
+
+ if (cnt == 0) {
+ /* 0-byte send from DSP */
+ unuse_ipbuf_nowait(ipb_h);
+ goto done;
+ }
+ ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+ /* we keep coming bid and return alternative line to DSP. */
+ balance_ipbuf();
+
+done:
+ wake_up_interruptible(&task->dev->read_wait_q);
+ return;
+
+unuse_ipbuf_out:
+ unuse_ipbuf_nowait(ipb_h);
+ return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ u16 cnt = mb->data;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_pvt(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from private receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQ from passive receiving task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = cnt*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+ u16 bid = mb->data;
+ struct ipbuf_head *ipb_h;
+
+ if (bid >= ipbcfg.ln) {
+ printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+ return;
+ }
+ ipb_h = bid_to_ipbuf(bid);
+
+ /* should be done in DSP, but just in case. */
+ ipb_h->p->next = BID_NULL;
+
+ /* we don't need to sync with DSP */
+ ipb_bsycnt_dec(&ipbcfg);
+ release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (sndtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+ return;
+ }
+ if (sndtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKSNDP from non-private sending task! (task%d)\n",
+ tid);
+ return;
+ }
+
+ /*
+ * we should not have delayed block at this point
+ * because read() routine releases the lock of the buffer and
+ * until then DSP can't send next data.
+ */
+
+ ipbp = task->ipbuf_pvt_r;
+ if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+ wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+ struct ipbuf_p *ipbp;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+ return;
+ }
+ if (rcvtyp_wd(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_gbl(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+ return;
+ }
+ if (rcvtyp_psv(task->ttyp)) {
+ printk(KERN_ERR
+ "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+ return;
+ }
+
+ ipbp = task->ipbuf_pvt_w;
+ if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+ printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+ return;
+ }
+ pr_debug("mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+ MKLONG(ipbp->ah, ipbp->al));
+ dev = task->dev;
+ spin_lock(&dev->wsz_lock);
+ dev->wsz = ipbp->c*2;
+ spin_unlock(&dev->wsz_lock);
+ wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+ return;
+ }
+
+ if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+ printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+ return;
+ }
+
+ task->dev->tctl_stat = mb->data;
+ wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ struct dsptask *task = dsptask[tid];
+ u16 *tnm;
+ volatile u16 *buf;
+ int i;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+ return;
+ }
+ if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+ printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+ return;
+ }
+
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+ dsp_mem_disable(ipbuf_sys_da);
+ goto out;
+ }
+
+ /*
+ * read configuration data on system IPBUF
+ */
+ buf = ipbuf_sys_da->d;
+ task->ttyp = buf[0];
+ task->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);
+ dsp_mem_disable(ipbuf_sys_da);
+
+ /*
+ * copy task name string
+ */
+ if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+ task->name[0] = '\0';
+ goto out;
+ }
+
+ for (i = 0; i < TNM_LEN-1; i++) {
+ /* avoiding byte access */
+ u16 tmp = tnm[i];
+ task->name[i] = tmp & 0x00ff;
+ if (!tmp)
+ break;
+ }
+ task->name[TNM_LEN-1] = '\0';
+
+ task->state = TASK_ST_READY;
+out:
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+ printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+
+ if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+ printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+ return;
+ }
+ cfg_tid = tid;
+ wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct taskdev *dev;
+
+ if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+ printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+ return;
+ }
+
+ /* wake up waiting processes */
+ dev = task->dev;
+ wake_up_interruptible_all(&dev->read_wait_q);
+ wake_up_interruptible_all(&dev->write_wait_q);
+ wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_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 mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ int cnt = mb->data;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ int i;
+
+#ifdef OLD_BINARY_SUPPORT
+ if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+ mbox_dbg_old(mb);
+ return;
+ }
+#endif
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dbg_buf == NULL) {
+ printk(KERN_ERR "mbox: 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++) {
+ u16 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';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_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 mbox_dbg_old(struct mbcmd *mb)
+{
+ u8 tid = mb->cmd_l;
+ char s[80], *s_end = &s[79], *p;
+ u16 *src;
+ volatile u16 *buf;
+ int cnt;
+ int i;
+
+ if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+ (tid != TID_ANON)) {
+ printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+ return;
+ }
+ if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+ printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+ return;
+ }
+ if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+ printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+ goto out1;
+ }
+ buf = ipbuf_sys_da->d;
+ cnt = buf[0];
+ src = MKVIRT(buf[1], buf[2]);
+ if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+ goto out2;
+
+ if (dsp_mem_enable(src) < 0)
+ goto out2;
+
+ p = s;
+ for (i = 0; i < cnt; i++) {
+ u16 tmp;
+ /*
+ * Be carefull that ipbuf 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';
+ pr_info("%s", s);
+ p = s;
+ continue;
+ }
+ if (p == s_end) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ p = s;
+ continue;
+ }
+ }
+ if (p > s) {
+ *p = '\0';
+ pr_info("%s\n", s);
+ }
+
+ dsp_mem_disable(src);
+out2:
+ release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+ dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev;
+ struct proc_list *pl;
+ int len = 0;
+
+ dev = to_taskdev(d);
+ spin_lock(&dev->proc_list_lock);
+ list_for_each_entry(pl, &dev->proc_list, list_head) {
+ /* need to lock tasklist_lock before calling
+ * find_task_by_pid_type. */
+ if (find_task_by_pid(pl->pid) != NULL)
+ len += sprintf(buf + len, "%d\n", pl->pid);
+ read_unlock(&tasklist_lock);
+ }
+ spin_unlock(&dev->proc_list_lock);
+
+ return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ int len;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ len = sprintf(buf, "%s\n", dev->task->name);
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct taskdev *dev = to_taskdev(d);
+ u16 ttyp;
+ int len = 0;
+
+ if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+ return -ENODEV;
+
+ ttyp = dev->task->ttyp;
+ len += sprintf(buf + len, "0x%04x\n", ttyp);
+ len += sprintf(buf + len, "%s %s send\n",
+ (sndtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (sndtyp_wd(ttyp)) ? "word" :
+ (sndtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+ len += sprintf(buf + len, "%s %s receive\n",
+ (rcvtyp_acv(ttyp)) ? "active" :
+ "passive",
+ (rcvtyp_wd(ttyp)) ? "word" :
+ (rcvtyp_pvt(ttyp)) ? "private block" :
+ "global block");
+
+ devstate_read_unlock(dev);
+ return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct taskdev *dev = to_taskdev(d);
+ unsigned long fifosz;
+ int ret;
+
+ fifosz = simple_strtol(buf, NULL, 10);
+ if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+ return -ENODEV;
+ ret = taskdev_set_fifosz(dev, fifosz);
+ taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+
+ return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+ return sprintf(buf, "%d\n", fifo->size);
+}
+
+/* ipblink */
+static inline char *bid_name(u16 bid)
+{
+ static char s[6];
+
+ switch (bid) {
+ case BID_NULL:
+ return "NULL";
+ case BID_PVT:
+ return "PRIVATE";
+ default:
+ sprintf(s, "%d", bid);
+ return s;
+ }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+ int len;
+
+ spin_lock(&rcvdt->link.lock);
+ len = sprintf(buf, "top %s\ntail %s\n",
+ bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+ spin_unlock(&rcvdt->link.lock);
+
+ return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct dsptask *task = to_taskdev(d)->task;
+ return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+ struct dsptask *task = dsptask[tid];
+ struct ipblink *link;
+ u16 b;
+ int ret = 0;
+
+ if (task == NULL)
+ return 0;
+
+ link = &task->dev->rcvdt.bk.link;
+ spin_lock(&link->lock);
+ ipblink_for_each(b, link) {
+ if (b == bid) { /* found */
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&link->lock);
+
+ return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+ int retval;
+
+ memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+ memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+ retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+ &dsp_task_fops);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "omapdsp: failed to register task device: %d\n", retval);
+ return retval;
+ }
+
+ retval = bus_register(&dsptask_bus);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task bus: %d\n",
+ retval);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ retval = driver_register(&dsptask_driver);
+ if (retval) {
+ printk(KERN_ERR
+ "omapdsp: failed to register DSP task driver: %d\n",
+ retval);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+ dsp_task_class = class_create(THIS_MODULE, "dsptask");
+ if (IS_ERR(dsp_task_class)) {
+ printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+ class_destroy(dsp_task_class);
+ driver_unregister(&dsptask_driver);
+ bus_unregister(&dsptask_bus);
+ unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
diff --git a/drivers/dsp/dspgateway/taskwatch.c b/drivers/dsp/dspgateway/taskwatch.c
new file mode 100644
index 0000000..4297b51
--- /dev/null
+++ b/drivers/dsp/dspgateway/taskwatch.c
@@ -0,0 +1,163 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/arch/dsp.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
+static unsigned int change_cnt;
+
+void dsp_twch_touch(void)
+{
+ change_cnt++;
+ wake_up_interruptible(&read_wait_q);
+}
+
+/*
+ * @count: represents the device counts of the user's interst
+ */
+static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ long taskstat[TASKDEV_MAX];
+ int devcount = count / sizeof(long);
+ int i;
+ DEFINE_WAIT(wait);
+
+ if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+ printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+ return -EINVAL;
+ }
+
+ prepare_to_wait(&read_wait_q, &wait, TASK_INTERRUPTIBLE);
+ if (change_cnt == 0) /* last check */
+ schedule();
+ finish_wait(&read_wait_q, &wait);
+
+ /* unconfigured while waiting ;-( */
+ if ((change_cnt == 0) && (dsp_cfgstat_get_stat() != CFGSTAT_READY))
+ return -EINVAL;
+
+ if (devcount > TASKDEV_MAX)
+ devcount = TASKDEV_MAX;
+
+ count = devcount * sizeof(long);
+ change_cnt = 0;
+ for (i = 0; i < devcount; 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))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(file, &read_wait_q, wait);
+ if (change_cnt)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static int dsp_twch_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ switch (cmd) {
+ case TWCH_IOCTL_MKDEV:
+ {
+ char name[TNM_LEN];
+ if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+ return -EFAULT;
+ name[TNM_LEN-1] = '\0';
+ ret = dsp_mkdev(name);
+ break;
+ }
+
+ case TWCH_IOCTL_RMDEV:
+ {
+ char name[TNM_LEN];
+ if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+ return -EFAULT;
+ name[TNM_LEN-1] = '\0';
+ ret = dsp_rmdev(name);
+ break;
+ }
+
+ case TWCH_IOCTL_TADD:
+ {
+ struct omap_dsp_taddinfo ti;
+ if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
+ return -EFAULT;
+ ret = dsp_tadd_minor(ti.minor, ti.taskadr);
+ break;
+ }
+
+ case TWCH_IOCTL_TDEL:
+ ret = dsp_tdel_minor(arg);
+ break;
+
+ case TWCH_IOCTL_TKILL:
+ ret = dsp_tkill_minor(arg);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+struct file_operations dsp_twch_fops = {
+ .owner = THIS_MODULE,
+ .read = dsp_twch_read,
+ .poll = dsp_twch_poll,
+ .ioctl = dsp_twch_ioctl,
+};
+
+void dsp_twch_start(void)
+{
+ change_cnt = 1; /* first read will not wait */
+}
+
+void dsp_twch_stop(void)
+{
+ wake_up_interruptible(&read_wait_q);
+}
diff --git a/drivers/dsp/dspgateway/uaccess_dsp.S b/drivers/dsp/dspgateway/uaccess_dsp.S
new file mode 100644
index 0000000..bcf4a54
--- /dev/null
+++ b/drivers/dsp/dspgateway/uaccess_dsp.S
@@ -0,0 +1,77 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+
+/* Prototype: int __copy_to_user_dsp_2b(void *to, const char *from)
+ * Purpose : copy 2 bytes to user memory from kernel(DSP) memory
+ * escaping from unexpected byte swap using __copy_to_user()
+ * in OMAP architecture.
+ * Params : to - user memory
+ * : from - kernel(DSP) memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__copy_to_user_dsp_2b)
+ stmfd sp!, {r4, lr}
+ ldrb r3, [r1], #1
+ ldrb r4, [r1], #1
+USER( strbt r4, [r0], #1) @ May fault
+USER( strbt r3, [r0], #1) @ May fault
+ mov r0, #0
+ ldmfd sp!, {r4, pc}
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r0, #2
+ ldmfd sp!, {r4, pc}
+ .previous
+
+/* Prototype: unsigned long __copy_from_user_dsp_2b(void *to, const void *from);
+ * Purpose : copy 2 bytes from user memory to kernel(DSP) memory
+ * escaping from unexpected byte swap using __copy_to_user()
+ * in OMAP architecture.
+ * Params : to - kernel (DSP) memory
+ * : from - user memory
+ * Returns : success = 0, failure = 2
+ */
+
+ENTRY(__copy_from_user_dsp_2b)
+ stmfd sp!, {r4, lr}
+USER( ldrbt r3, [r1], #1) @ May fault
+USER( ldrbt r4, [r1], #1) @ May fault
+ strb r4, [r0], #1
+ strb r3, [r0], #1
+ mov r0, #0
+ ldmfd sp!, {r4, pc}
+
+ .section .fixup,"ax"
+ .align 0
+9001: mov r3, #0
+ strh r3, [r0], #2
+ mov r0, #2
+ ldmfd sp!, {r4, pc}
+ .previous
diff --git a/drivers/dsp/dspgateway/uaccess_dsp.h b/drivers/dsp/dspgateway/uaccess_dsp.h
new file mode 100644
index 0000000..028814f
--- /dev/null
+++ b/drivers/dsp/dspgateway/uaccess_dsp.h
@@ -0,0 +1,176 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+#include <asm/arch/dsp_common.h>
+#include "dsp.h"
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __copy_from_user_dsp_2b(void *to,
+ const void __user *from);
+extern unsigned long __copy_to_user_dsp_2b(void __user *to,
+ const void *from);
+#endif
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_from_user_dsp_2b(void *to,
+ const void *from)
+{
+ unsigned short tmp;
+
+ if (__copy_from_user(&tmp, from, 2))
+ return 2;
+ /* expecting compiler to generate "strh" instruction */
+ *((unsigned short *)to) = tmp;
+ return 0;
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_from_user_dsp(void *to, const void *from,
+ unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n)) {
+ if ((is_dsp_internal_mem(to)) &&
+ (((unsigned long)to & 2) || (n & 2))) {
+ /*
+ * DARAM/SARAM with odd word alignment
+ */
+ unsigned long n4;
+ unsigned long last_n;
+
+ /* dest not aligned -- copy 2 bytes */
+ if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_from_user_dsp_2b(to, from))
+#else
+ if (copy_from_user_dsp_2b(to, from))
+#endif
+ return n;
+ to += 2;
+ from += 2;
+ n -= 2;
+ }
+ /* middle 4*n bytes */
+ last_n = n & 2;
+ n4 = n - last_n;
+ if ((n = __copy_from_user(to, from, n4)) != 0)
+ return n + last_n;
+ /* last 2 bytes */
+ if (last_n) {
+ to += n4;
+ from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_from_user_dsp_2b(to, from))
+#else
+ if (copy_from_user_dsp_2b(to, from))
+#endif
+ return 2;
+ n = 0;
+ }
+ } else {
+ /*
+ * DARAM/SARAM with 4-byte alignment or
+ * external memory
+ */
+ n = __copy_from_user(to, from, n);
+ }
+ }
+ else /* security hole - plug it */
+ memzero(to, n);
+ return n;
+}
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_to_user_dsp_2b(void *to, const void *from)
+{
+ /* expecting compiler to generate "strh" instruction */
+ unsigned short tmp = *(unsigned short *)from;
+
+ return __copy_to_user(to, &tmp, 2);
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_to_user_dsp(void *to, const void *from,
+ unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n)) {
+ if ((is_dsp_internal_mem(from)) &&
+ (((unsigned long)to & 2) || (n & 2))) {
+ /*
+ * DARAM/SARAM with odd word alignment
+ */
+ unsigned long n4;
+ unsigned long last_n;
+
+ /* dest not aligned -- copy 2 bytes */
+ if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_to_user_dsp_2b(to, from))
+#else
+ if (copy_to_user_dsp_2b(to, from))
+#endif
+ return n;
+ to += 2;
+ from += 2;
+ n -= 2;
+ }
+ /* middle 4*n bytes */
+ last_n = n & 2;
+ n4 = n - last_n;
+ if ((n = __copy_to_user(to, from, n4)) != 0)
+ return n + last_n;
+ /* last 2 bytes */
+ if (last_n) {
+ to += n4;
+ from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+ if (__copy_to_user_dsp_2b(to, from))
+#else
+ if (copy_to_user_dsp_2b(to, from))
+#endif
+ return 2;
+ n = 0;
+ }
+ } else {
+ /*
+ * DARAM/SARAM with 4-byte alignment or
+ * external memory
+ */
+ n = __copy_to_user(to, from, n);
+ }
+ }
+ return n;
+}
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
diff --git a/include/asm-arm/arch-omap/mmu.h b/include/asm-arm/arch-omap/mmu.h
index 6c5869c..714ee1d 100644
--- a/include/asm-arm/arch-omap/mmu.h
+++ b/include/asm-arm/arch-omap/mmu.h
@@ -59,6 +59,16 @@ struct omap_mmu_tlb_lock {
struct omap_mmu;
struct omap_mmu_tlb_entry;
+#ifdef CONFIG_ARCH_OMAP1
+extern struct omap_mmu_ops omap1_mmu_ops;
+extern void omap_mmu_itack(struct omap_mmu *mmu);
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct omap_mmu_ops omap2_mmu_ops;
+static inline void omap_mmu_itack(struct omap_mmu *mmu)
+{
+}
+#endif
+
struct omap_mmu_ops {
int (*startup)(struct omap_mmu *mmu);
void (*shutdown)(struct omap_mmu *mmu);
--
1.5.3.6.GIT
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next prev parent reply other threads:[~2007-11-28 5:20 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-28 5:18 [PATCH 1/2] DSP: Move code to use only one dsp_common.h Tony Lindgren
2007-11-28 5:20 ` Tony Lindgren [this message]
2007-11-28 9:54 ` Hiroshi DOYU
2007-11-28 16:57 ` Tony Lindgren
2007-11-28 23:35 ` Tony Lindgren
2007-11-29 17:03 ` Hiroshi DOYU
2007-11-29 17:55 ` Tony Lindgren
2007-11-30 20:02 ` Tony Lindgren
2007-12-03 8:56 ` Hiroshi DOYU
2007-12-03 10:33 ` Trilok Soni
2007-12-03 11:03 ` Hiroshi DOYU
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071128052005.GJ11825@atomide.com \
--to=tony@atomide.com \
--cc=Hiroshi.DOYU@nokia.com \
--cc=linux-omap-open-source@linux.omap.com \
--cc=linux-omap@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox