From 848a8f949e85cb6c8dfa780f20337007f79be6d7 Mon Sep 17 00:00:00 2001 From: Toshihiro Kobayashi Date: Thu, 21 Sep 2006 17:41:36 +0300 Subject: [PATCH] ARM: OMAP: DSPGW: DSP Gateway driver 3.3.1 Here's the patch that updates DSP Gateway driver to 3.3.1, that supports omap2 DSP. It also contains generic mailbox interface considering IVA use on 2420, but this patch itself doesn't contain any IVA driver. Regarding omap2, this code is tested only on our 2420 custom board, so feedbacks from testing on other chips / boards will be greatly appreciated. Signed-off-by: Hiroshi DOYU Signed-off-by: Juha Yrjola --- arch/arm/mach-omap1/Kconfig | 2 - arch/arm/mach-omap2/io.c | 18 + arch/arm/plat-omap/Kconfig | 2 + arch/arm/plat-omap/Makefile | 2 +- arch/arm/plat-omap/dsp/Kconfig | 2 +- arch/arm/plat-omap/dsp/dsp.h | 225 +-- arch/arm/plat-omap/dsp/dsp_common.c | 169 +- arch/arm/plat-omap/dsp/dsp_common.h | 149 +- arch/arm/plat-omap/dsp/dsp_core.c | 668 +++----- arch/arm/plat-omap/dsp/dsp_ctl.c | 959 ++++++------ arch/arm/plat-omap/dsp/dsp_ctl_core.c | 34 +- arch/arm/plat-omap/dsp/dsp_mbcmd.h | 107 ++ arch/arm/plat-omap/dsp/dsp_mem.c | 1368 +++++++++++----- arch/arm/plat-omap/dsp/error.c | 146 +- arch/arm/plat-omap/dsp/fifo.h | 45 +- arch/arm/plat-omap/dsp/hardware_dsp.h | 208 +-- arch/arm/plat-omap/dsp/ioctl.h | 115 ++ arch/arm/plat-omap/dsp/ipbuf.c | 158 +- arch/arm/plat-omap/dsp/ipbuf.h | 181 ++- arch/arm/plat-omap/dsp/mblog.c | 218 ++- arch/arm/plat-omap/dsp/omap1_dsp.h | 188 +++ arch/arm/plat-omap/dsp/omap2_dsp.h | 158 ++ arch/arm/plat-omap/dsp/proclist.h | 91 +- arch/arm/plat-omap/dsp/task.c | 1967 +++++++++++++----------- arch/arm/plat-omap/dsp/taskwatch.c | 91 +- arch/arm/plat-omap/dsp/uaccess_dsp.S | 27 +- arch/arm/plat-omap/dsp/uaccess_dsp.h | 37 +- arch/arm/plat-omap/mailbox.c | 574 +++++++ arch/arm/plat-omap/mailbox_hw.h | 79 + include/asm-arm/arch-omap/dsp.h | 250 --- include/asm-arm/arch-omap/dsp_common.h | 29 +- include/asm-arm/arch-omap/io.h | 11 + include/asm-arm/arch-omap/irqs.h | 13 +- include/asm-arm/arch-omap/mailbox.h | 54 + include/asm-arm/arch-omap/omap24xx.h | 6 + 35 files changed, 4975 insertions(+), 3376 deletions(-) create mode 100644 arch/arm/plat-omap/dsp/dsp_mbcmd.h create mode 100644 arch/arm/plat-omap/dsp/ioctl.h create mode 100644 arch/arm/plat-omap/dsp/omap1_dsp.h create mode 100644 arch/arm/plat-omap/dsp/omap2_dsp.h create mode 100644 arch/arm/plat-omap/mailbox.c create mode 100644 arch/arm/plat-omap/mailbox_hw.h delete mode 100644 include/asm-arm/arch-omap/dsp.h create mode 100644 include/asm-arm/arch-omap/mailbox.h diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 781f0d4ea3e..ab1b17d35bd 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -179,5 +179,3 @@ config OMAP_ARM_30MHZ help Enable 30MHz clock for OMAP CPU. If unsure, say N. -source "arch/arm/plat-omap/dsp/Kconfig" - diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index a0728c33e5d..df251fefc48 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -44,6 +44,24 @@ static struct map_desc omap2_io_desc[] __initdata = { .pfn = __phys_to_pfn(L4_24XX_PHYS), .length = L4_24XX_SIZE, .type = MT_DEVICE + }, + { + .virtual = DSP_MEM_24XX_VIRT, + .pfn = __phys_to_pfn(DSP_MEM_24XX_PHYS), + .length = DSP_MEM_24XX_SIZE, + .type = MT_DEVICE + }, + { + .virtual = DSP_IPI_24XX_VIRT, + .pfn = __phys_to_pfn(DSP_IPI_24XX_PHYS), + .length = DSP_IPI_24XX_SIZE, + .type = MT_DEVICE + }, + { + .virtual = DSP_MMU_24XX_VIRT, + .pfn = __phys_to_pfn(DSP_MMU_24XX_PHYS), + .length = DSP_MMU_24XX_SIZE, + .type = MT_DEVICE } }; diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 75f14947149..2b56996154a 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -172,6 +172,8 @@ 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 6a3a3e81484..e49bef89bf3 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -26,4 +26,4 @@ obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o # DSP subsystem -obj-y += dsp/ +obj-$(CONFIG_OMAP_DSP) += dsp/ mailbox.o diff --git a/arch/arm/plat-omap/dsp/Kconfig b/arch/arm/plat-omap/dsp/Kconfig index 47f06b21e2e..71da40bc538 100644 --- a/arch/arm/plat-omap/dsp/Kconfig +++ b/arch/arm/plat-omap/dsp/Kconfig @@ -1,7 +1,7 @@ config OMAP_DSP tristate "OMAP DSP driver (DSP Gateway)" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX + depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX help This enables OMAP DSP driver, DSP Gateway. diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h index 48974ad271a..8ec81a99339 100644 --- a/arch/arm/plat-omap/dsp/dsp.h +++ b/arch/arm/plat-omap/dsp/dsp.h @@ -1,32 +1,36 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Header for OMAP DSP driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/09: DSP Gateway version 3.3 */ +#include #include "hardware_dsp.h" #include "dsp_common.h" +/* + * 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 @@ -35,9 +39,12 @@ #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) @@ -50,30 +57,37 @@ enum dsp_mem_type_e { MEM_TYPE_EXTERN, }; -enum arm_dsp_dir { +enum arm_dsp_dir_e { DIR_A2D, DIR_D2A, }; -/* - * INT_D2A_MB value definition - * INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox - * INT_DSP_MAILBOX2: use Mailbox 2 (INT 11) for DSP->ARM mailbox - */ -#define INT_D2A_MB1 INT_DSP_MAILBOX1 +enum cfgstat_e { + CFGSTAT_CLEAN = 0, + CFGSTAT_READY, + CFGSTAT_SUSPEND, + CFGSTAT_RESUME, /* request only */ + CFGSTAT_MAX +}; -/* keep 2 entries for OMAP_DSP_TID_FREE and OMAP_DSP_TID_ANON */ +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))); -#define MBCMD(nm) OMAP_DSP_MBCMD_##nm struct sync_seq { - unsigned short da_dsp; - unsigned short da_arm; - unsigned short ad_dsp; - unsigned short ad_arm; + u16 da_dsp; + u16 da_arm; + u16 ad_dsp; + u16 ad_arm; }; struct mem_sync_struct { @@ -82,93 +96,106 @@ struct mem_sync_struct { struct sync_seq *SDRAM; }; -/* struct mbcmd and struct mbcmd_hw must be compatible */ +/* struct mbcmd and union mbcmd_hw must be compatible */ struct mbcmd { - unsigned short cmd_l:8; - unsigned short cmd_h:7; - unsigned short seq:1; - unsigned short data; -}; - -struct mbcmd_hw { - unsigned short cmd; - unsigned short data; + u32 data:16; + u32 cmd_l:8; + u32 cmd_h:7; + u32 seq:1; }; -#define mbcmd_set(mb, h, l, d) \ - do { \ - (mb).cmd_h = (h); \ - (mb).cmd_l = (l); \ - (mb).data = (d); \ - } while(0) +#define MBCMD_INIT(h, l, d) { \ + .cmd_h = (h), \ + .cmd_l = (l), \ + .data = (d), \ + } struct mb_exarg { - unsigned char tid; + u8 tid; int argc; - unsigned short *argv; + u16 *argv; }; -extern void dsp_mb_start(void); -extern void dsp_mb_stop(void); -extern int dsp_mb_config(void *p); -extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid, - int try_cnt); -extern int __mbcmd_send(struct mbcmd *mb); -extern int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, - int recovery_flag); -#define dsp_mbcmd_send(mb) __dsp_mbcmd_send(mb, NULL, 0) -#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send(mb, arg, 0) -extern int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg, - wait_queue_head_t *q); +extern struct mbx *mbx_dsp; +extern void dsp_mbx_start(void); +extern void dsp_mbx_stop(void); +extern int dsp_mbx_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(mb, NULL, q) -#define dsp_mbcmd_send_and_wait_exarg(mb, arg, q) \ - __dsp_mbcmd_send_and_wait(mb, arg, q) -int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data, - int recovery_flag); -#define dsp_mbsend(cmdh, cmdl, data) \ - __dsp_mbsend(cmdh, cmdl, data, 0) -#define dsp_mbsend_recovery(cmdh, cmdl, data) \ - __dsp_mbsend(cmdh, cmdl, data, 1) - + 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(MBX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0) +#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \ + __mbcompose_send_exarg(MBX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0) +#define mbcompose_send_recovery(cmd_h, cmd_l, data) \ + __mbcompose_send_exarg(MBX_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(MBX_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(MBX_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(unsigned short ln, unsigned short lsz, void *base); -extern int ipbuf_sys_config(void *p, enum arm_dsp_dir dir); -extern int ipbuf_p_validate(void *p, enum arm_dsp_dir dir); -extern unsigned short get_free_ipbuf(unsigned char tid); -extern void unuse_ipbuf_nowait(unsigned short bid); -extern void unuse_ipbuf(unsigned short bid); -extern void release_ipbuf(unsigned short bid); +extern int ipbuf_config(u16 ln, u16 lsz, void *base); +extern int ipbuf_sys_config(void *p, enum arm_dsp_dir_e dir); +extern int ipbuf_p_validate(void *p, enum arm_dsp_dir_e 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 = OMAP_DSP_TID_FREE; \ + (ipbuf_pvt)->s = TID_FREE; \ } while(0) extern int mbx_revision; -extern int dsp_is_ready(void); -extern int dspuncfg(void); -extern void dsp_runlevel(unsigned char level); -extern int dsp_suspend(void); -extern int dsp_resume(void); +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(unsigned char n); +extern int dsp_task_config_all(u8 n); extern void dsp_task_unconfig_all(void); -extern unsigned char dsp_task_count(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(unsigned char minor, unsigned long adr); -extern int dsp_tdel(unsigned char minor); -extern int dsp_tkill(unsigned char minor); +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(short *buf, unsigned short sz, unsigned short lsz); +extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz); extern void dsp_dbg_stop(void); -extern int ipbuf_is_held(unsigned char tid, unsigned short bid); +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); @@ -176,7 +203,9 @@ extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len); extern int dsp_address_validate(void *p, size_t len, char *fmt, ...); extern int dsp_mem_enable(void *adr); extern void dsp_mem_disable(void *adr); +#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); @@ -189,13 +218,11 @@ extern void dsp_twch_touch(void); extern void dsp_err_start(void); extern void dsp_err_stop(void); -extern void dsp_err_mmu_set(unsigned long adr); -extern void dsp_err_mmu_clear(void); -extern int dsp_err_mmu_isset(void); -extern void dsp_err_wdt_clear(void); -extern int dsp_err_wdt_isset(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 { +enum cmd_l_type_e { CMD_L_TYPE_NULL, CMD_L_TYPE_TID, CMD_L_TYPE_SUBCMD, @@ -203,7 +230,7 @@ enum cmd_l_type { struct cmdinfo { char *name; - enum cmd_l_type cmd_l_type; + enum cmd_l_type_e cmd_l_type; void (*handler)(struct mbcmd *mb); }; @@ -212,15 +239,11 @@ 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, enum arm_dsp_dir dir); +extern void mblog_add(struct mbcmd *mb, enum arm_dsp_dir_e dir); #ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE -extern void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir); +extern void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir_e dir); #else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ #define mblog_printcmd(mb, dir) do {} while(0) #endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ -#ifdef CONFIG_PROC_FS -extern struct proc_dir_entry *procdir_dsp; -#endif /* CONFIG_PROC_FS */ - extern struct platform_device dsp_device; diff --git a/arch/arm/plat-omap/dsp/dsp_common.c b/arch/arm/plat-omap/dsp/dsp_common.c index 378d564fbaa..4c35df80885 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.c +++ b/arch/arm/plat-omap/dsp/dsp_common.c @@ -1,31 +1,27 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_common.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP driver static part + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/13: DSP Gateway version 3.3 */ #include -#include #include #include #include @@ -36,21 +32,34 @@ #include #include #include -#include +#ifdef CONFIG_ARCH_OMAP1 #include +#endif #include "dsp_common.h" +#if defined(CONFIG_ARCH_OMAP1) +#define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG) +#elif defined(CONFIG_ARCH_OMAP2) +#define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG) +#endif + +#if defined(CONFIG_ARCH_OMAP1) struct clk *dsp_ck_handle; struct clk *api_ck_handle; -unsigned long dspmem_base, dspmem_size, - daram_base, daram_size, - saram_base, saram_size; +#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; struct cpustat { struct mutex lock; - enum e_cpustat stat; - enum e_cpustat req; - unsigned short icrmask; + enum cpustat_e stat; + enum cpustat_e req; + u16 icrmask; +#ifdef CONFIG_ARCH_OMAP1 struct { int mpui; int mem; @@ -58,13 +67,13 @@ struct cpustat { } usecount; int (*mem_req_cb)(void); void (*mem_rel_cb)(void); -}; -struct cpustat cpustat = { +#endif +} cpustat = { .stat = CPUSTAT_RESET, .icrmask = 0xffff, }; -int dsp_set_rstvect(unsigned long adr) +int dsp_set_rstvect(dsp_long_t adr) { unsigned long *dst_adr; @@ -75,17 +84,26 @@ int dsp_set_rstvect(unsigned long adr) /* word swap */ *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16); /* fill 8 bytes! */ - *(dst_adr+1) = 0; + *(dst_adr + 1) = 0; /* direct boot */ - omap_writew(MPUI_DSP_BOOT_CONFIG_DIRECT, MPUI_DSP_BOOT_CONFIG); + dsp_boot_config(DSP_BOOT_CONFIG_DIRECT); return 0; } -static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len) +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; - unsigned short *src = (unsigned short *)src_c; + u16 *src = (u16 *)src_c; int len_w; /* len must be multiple of 2. */ @@ -165,7 +183,7 @@ static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len) * DSP Gateway driver will overwrite this value with other value, * to avoid confliction with the user program. */ -static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI; +static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI; static void dsp_gbl_idle(void) { @@ -175,12 +193,12 @@ static void dsp_gbl_idle(void) clk_enable(api_ck_handle); #if 0 - omap_writew(MPUI_DSP_BOOT_CONFIG_IDLE, MPUI_DSP_BOOT_CONFIG); + 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) - omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG); + dsp_boot_config(DSP_BOOT_CONFIG_MPUI); else dsp_set_rstvect(idle_boot_base); @@ -191,7 +209,7 @@ static void dsp_gbl_idle(void) static void dsp_cpu_idle(void) { - unsigned short icr_tmp; + u16 icr_tmp; unsigned char icrh, icrl; __dsp_reset(); @@ -202,8 +220,7 @@ static void dsp_cpu_idle(void) * 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_IDLE_DOMAIN | - DSPREG_ICR_DPLL_IDLE_DOMAIN); + icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL); icrh = icr_tmp >> 8; icrl = icr_tmp & 0xff; { @@ -212,7 +229,7 @@ static void dsp_cpu_idle(void) CPU_IDLE_TEXT_SIZE); } if (idle_boot_base == DSP_BOOT_ADR_MPUI) - omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG); + dsp_boot_config(DSP_BOOT_CONFIG_MPUI); else dsp_set_rstvect(idle_boot_base); __dsp_run(); @@ -220,7 +237,7 @@ static void dsp_cpu_idle(void) clk_disable(api_ck_handle); } -void dsp_set_idle_boot_base(unsigned long adr, size_t size) +void dsp_set_idle_boot_base(dsp_long_t adr, size_t size) { if (adr == idle_boot_base) return; @@ -239,6 +256,13 @@ void dsp_set_idle_boot_base(unsigned long adr, size_t size) dsp_cpu_idle(); } +void dsp_reset_idle_boot_base(void) +{ + idle_boot_base = DSP_BOOT_ADR_MPUI; +} + +#endif /* CONFIG_ARCH_OMAP1 */ + static int init_done; static int __init omap_dsp_init(void) @@ -265,19 +289,30 @@ static int __init omap_dsp_init(void) 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 if (dspmem_size == 0) { printk(KERN_ERR "omapdsp: unsupported omap architecture.\n"); return -ENODEV; } - dsp_ck_handle = clk_get(0, "dsp_ck"); +#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(0, "api_ck"); + 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"); return PTR_ERR(api_ck_handle); @@ -290,18 +325,33 @@ static int __init omap_dsp_init(void) 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"); + return PTR_ERR(dsp_ick_handle); + } +#endif init_done = 1; printk(KERN_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) { @@ -310,23 +360,32 @@ static void dsp_cpustat_update(void) 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; enable_irq(INT_DSP_MMU); } return; } - /* cpustat.stat < CPUSTAT_RUN */ + /* cpustat.req < CPUSTAT_RUN */ if (cpustat.stat == CPUSTAT_RUN) { disable_irq(INT_DSP_MMU); +#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. @@ -355,17 +414,22 @@ static void dsp_cpustat_update(void) } 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 e_cpustat req) +void dsp_cpustat_request(enum cpustat_e req) { mutex_lock(&cpustat.lock); cpustat.req = req; @@ -373,17 +437,17 @@ void dsp_cpustat_request(enum e_cpustat req) mutex_unlock(&cpustat.lock); } -enum e_cpustat dsp_cpustat_get_stat(void) +enum cpustat_e dsp_cpustat_get_stat(void) { return cpustat.stat; } -unsigned short dsp_cpustat_get_icrmask(void) +u16 dsp_cpustat_get_icrmask(void) { return cpustat.icrmask; } -void dsp_cpustat_set_icrmask(unsigned short mask) +void dsp_cpustat_set_icrmask(u16 mask) { mutex_lock(&cpustat.lock); cpustat.icrmask = mask; @@ -391,6 +455,7 @@ void dsp_cpustat_set_icrmask(unsigned short mask) mutex_unlock(&cpustat.lock); } +#ifdef CONFIG_ARCH_OMAP1 void omap_dsp_request_mpui(void) { mutex_lock(&cpustat.lock); @@ -499,6 +564,7 @@ void dsp_unregister_mem_cb(void) cpustat.mem_rel_cb = NULL; mutex_unlock(&cpustat.lock); } +#endif /* CONFIG_ARCH_OMAP1 */ /* * Audio power control function prototypes and defaults @@ -522,14 +588,21 @@ EXPORT_SYMBOL(omap_dsp_audio_pwr_down_request); 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(dspmem_base); EXPORT_SYMBOL(dspmem_size); EXPORT_SYMBOL(daram_base); @@ -537,13 +610,19 @@ 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); +#ifdef CONFIG_ARCH_OMAP1 EXPORT_SYMBOL(dsp_register_mem_cb); EXPORT_SYMBOL(dsp_unregister_mem_cb); +#endif /* CONFIG_ARCH_OMAP1 */ EXPORT_SYMBOL(__cpu_flush_kern_tlb_range); EXPORT_SYMBOL(cpu_architecture); diff --git a/arch/arm/plat-omap/dsp/dsp_common.h b/arch/arm/plat-omap/dsp/dsp_common.h index 36034bd8ae4..54fd2283b43 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.h +++ b/arch/arm/plat-omap/dsp/dsp_common.h @@ -1,29 +1,29 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_common.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Header for OMAP DSP driver static part + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/13: DSP Gateway version 3.3 */ +#ifndef DRIVER_DSP_COMMON_H +#define DRIVER_DSP_COMMON_H + #include "hardware_dsp.h" #define DSPSPACE_SIZE 0x1000000 @@ -36,48 +36,49 @@ 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) + +#if defined(CONFIG_ARCH_OMAP15XX) +#define INT_DSP_MMU INT_1510_DSP_MMU +#elif defined(CONFIG_ARCH_OMAP16XX) +#define INT_DSP_MMU INT_1610_DSP_MMU +#elif defined(CONFIG_ARCH_OMAP24XX) +#define INT_DSP_MMU INT_24XX_DSP_MMU +#endif #define dspword_to_virt(dw) ((void *)(dspmem_base + ((dw) << 1))) #define dspbyte_to_virt(db) ((void *)(dspmem_base + (db))) -#define virt_to_dspword(va) (((unsigned long)(va) - dspmem_base) >> 1) -#define virt_to_dspbyte(va) ((unsigned long)(va) - dspmem_base) +#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() \ - do { \ - omap_writel( \ - (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ - MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \ - } while(0) + omap_set_bits_regl(MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL_WORDSWAP_MASK, \ + MPUI_CTRL) #define mpui_wordswap_off() \ - do { \ - omap_writel( \ - (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ - MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \ - } while(0) + omap_set_bits_regl(MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL_WORDSWAP_MASK, \ + MPUI_CTRL) #define mpui_byteswap_on() \ - do { \ - omap_writel( \ - (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ - MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \ - } while(0) + omap_set_bits_regl(MPUI_CTRL_BYTESWAP_API, MPUI_CTRL_BYTESWAP_MASK, \ + MPUI_CTRL) #define mpui_byteswap_off() \ - do { \ - omap_writel( \ - (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ - MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \ - } while(0) + omap_set_bits_regl(MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL_BYTESWAP_MASK, \ + MPUI_CTRL) /* * TC wordswap on / off @@ -88,11 +89,7 @@ TC_ENDIANISM); \ } while(0) -#define tc_noswap() \ - do { \ - omap_writel(omap_readl(TC_ENDIANISM) & ~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 @@ -101,32 +98,60 @@ #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 + */ +#define RSTCTRL_RST1_DSP 0x00000001 +#define RSTCTRL_RST2_DSP 0x00000002 +#define __dsp_core_enable() \ + do { RM_RSTCTRL_DSP &= ~RSTCTRL_RST1_DSP; } while (0) +#define __dsp_core_disable() \ + do { RM_RSTCTRL_DSP |= RSTCTRL_RST1_DSP; } while (0) +#define __dsp_per_enable() \ + do { RM_RSTCTRL_DSP &= ~RSTCTRL_RST2_DSP; } while (0) +#define __dsp_per_disable() \ + do { RM_RSTCTRL_DSP |= RSTCTRL_RST2_DSP; } while (0) +#endif /* CONFIG_ARCH_OMAP2 */ + +typedef u32 dsp_long_t; /* must have ability to carry TADD_ABORTADR */ + +#if defined(CONFIG_ARCH_OMAP1) extern struct clk *dsp_ck_handle; extern struct clk *api_ck_handle; -extern unsigned long dspmem_base, dspmem_size, - daram_base, daram_size, - saram_base, saram_size; +#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 e_cpustat { +enum cpustat_e { CPUSTAT_RESET = 0, - CPUSTAT_GBL_IDLE = 1, - CPUSTAT_CPU_IDLE = 2, - CPUSTAT_RUN = 3 +#ifdef CONFIG_ARCH_OMAP1 + CPUSTAT_GBL_IDLE, + CPUSTAT_CPU_IDLE, +#endif + CPUSTAT_RUN, + CPUSTAT_MAX }; -#define cpustat_name(stat) \ - ((stat == CPUSTAT_RESET) ? "RESET" :\ - (stat == CPUSTAT_GBL_IDLE) ? "GBL_IDLE" :\ - (stat == CPUSTAT_CPU_IDLE) ? "CPU_IDLE" :\ - (stat == CPUSTAT_RUN) ? "RUN" :\ - "unknown") - -int dsp_set_rstvect(unsigned long adr); -void dsp_set_idle_boot_base(unsigned long adr, size_t size); -void dsp_cpustat_request(enum e_cpustat req); -enum e_cpustat dsp_cpustat_get_stat(void); -unsigned short dsp_cpustat_get_icrmask(void); -void dsp_cpustat_set_icrmask(unsigned short mask); +int dsp_set_rstvect(dsp_long_t adr); +dsp_long_t dsp_get_rstvect(void); +#ifdef CONFIG_ARCH_OMAP1 +void dsp_set_idle_boot_base(dsp_long_t adr, size_t size); +void dsp_reset_idle_boot_base(void); +#endif +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); +#ifdef CONFIG_ARCH_OMAP1 void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)); void dsp_unregister_mem_cb(void); +#endif + +#endif /* DRIVER_DSP_COMMON_H */ diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c index 2e1cdca0e63..39765890e13 100644 --- a/arch/arm/plat-omap/dsp/dsp_core.c +++ b/arch/arm/plat-omap/dsp/dsp_core.c @@ -1,174 +1,144 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_core.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/07: DSP Gateway version 3.3 */ #include #include -#include #include #include -#include -#include #include -#include -#include -#include +#include +#include #include -#include +#include #include -#include -#include "hardware_dsp.h" +#include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" - MODULE_AUTHOR("Toshihiro Kobayashi "); MODULE_DESCRIPTION("OMAP DSP driver module"); MODULE_LICENSE("GPL"); -enum mbseq_check_level { - MBSEQ_CHECK_NONE, /* no check */ - MBSEQ_CHECK_VERBOSE, /* discard the illegal command and - error report */ - MBSEQ_CHECK_SILENT, /* discard the illegal command */ -}; - -static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE; - -static int mbx1_valid; +struct mbx *mbx_dsp; static struct sync_seq *mbseq; -static unsigned short mbseq_expect_tmp; -static unsigned short *mbseq_expect = &mbseq_expect_tmp; +static u16 mbseq_expect_tmp; +static u16 *mbseq_expect = &mbseq_expect_tmp; /* * mailbox commands */ -extern void mbx1_wdsnd(struct mbcmd *mb); -extern void mbx1_wdreq(struct mbcmd *mb); -extern void mbx1_bksnd(struct mbcmd *mb); -extern void mbx1_bkreq(struct mbcmd *mb); -extern void mbx1_bkyld(struct mbcmd *mb); -extern void mbx1_bksndp(struct mbcmd *mb); -extern void mbx1_bkreqp(struct mbcmd *mb); -extern void mbx1_tctl(struct mbcmd *mb); -extern void mbx1_poll(struct mbcmd *mb); +extern void mbx_wdsnd(struct mbcmd *mb); +extern void mbx_wdreq(struct mbcmd *mb); +extern void mbx_bksnd(struct mbcmd *mb); +extern void mbx_bkreq(struct mbcmd *mb); +extern void mbx_bkyld(struct mbcmd *mb); +extern void mbx_bksndp(struct mbcmd *mb); +extern void mbx_bkreqp(struct mbcmd *mb); +extern void mbx_tctl(struct mbcmd *mb); +extern void mbx_poll(struct mbcmd *mb); #ifdef OLD_BINARY_SUPPORT /* v3.3 obsolete */ -extern void mbx1_wdt(struct mbcmd *mb); +extern void mbx_wdt(struct mbcmd *mb); #endif -extern void mbx1_suspend(struct mbcmd *mb); -static void mbx1_kfunc(struct mbcmd *mb); -extern void mbx1_tcfg(struct mbcmd *mb); -extern void mbx1_tadd(struct mbcmd *mb); -extern void mbx1_tdel(struct mbcmd *mb); -extern void mbx1_dspcfg(struct mbcmd *mb); -extern void mbx1_regrw(struct mbcmd *mb); -extern void mbx1_getvar(struct mbcmd *mb); -extern void mbx1_err(struct mbcmd *mb); -extern void mbx1_dbg(struct mbcmd *mb); +extern void mbx_suspend(struct mbcmd *mb); +static void mbx_kfunc(struct mbcmd *mb); +extern void mbx_tcfg(struct mbcmd *mb); +extern void mbx_tadd(struct mbcmd *mb); +extern void mbx_tdel(struct mbcmd *mb); +extern void mbx_dspcfg(struct mbcmd *mb); +extern void mbx_regrw(struct mbcmd *mb); +extern void mbx_getvar(struct mbcmd *mb); +extern void mbx_err(struct mbcmd *mb); +extern void mbx_dbg(struct mbcmd *mb); static const struct cmdinfo - cif_null = { "Unknown", CMD_L_TYPE_NULL, NULL }, - cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbx1_wdsnd }, - cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbx1_wdreq }, - cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbx1_bksnd }, - cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbx1_bkreq }, - cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbx1_bkyld }, - cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp }, - cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp }, - cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl }, - cif_poll = { "POLL", CMD_L_TYPE_NULL, mbx1_poll }, + cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbx_wdsnd }, + cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbx_wdreq }, + cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbx_bksnd }, + cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbx_bkreq }, + cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbx_bkyld }, + cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx_bksndp }, + cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx_bkreqp }, + cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx_tctl }, + cif_poll = { "POLL", CMD_L_TYPE_NULL, mbx_poll }, #ifdef OLD_BINARY_SUPPORT /* v3.3 obsolete */ - cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_wdt }, + cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx_wdt }, #endif - cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL }, - cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL }, - cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend }, - cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbx1_kfunc }, - cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbx1_tcfg }, - cif_tadd = { "TADD", CMD_L_TYPE_TID, mbx1_tadd }, - cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbx1_tdel }, - cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL }, - cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbx1_dspcfg }, - cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbx1_regrw }, - cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbx1_getvar }, - cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL }, - cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbx1_err }, - cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbx1_dbg }; - -const struct cmdinfo *cmdinfo[128] = { -/*00*/ &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*10*/ &cif_wdsnd, &cif_wdreq, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*20*/ &cif_bksnd, &cif_bkreq, &cif_null, &cif_bkyld, - &cif_bksndp, &cif_bkreqp, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*30*/ &cif_tctl, &cif_null, &cif_poll, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*40*/ &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, + cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL }, + cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL }, + cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx_suspend }, + cif_kfunc = { "KFUNC", CMD_L_TYPE_SUBCMD, mbx_kfunc }, + cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbx_tcfg }, + cif_tadd = { "TADD", CMD_L_TYPE_TID, mbx_tadd }, + cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbx_tdel }, + cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL }, + cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbx_dspcfg }, + cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbx_regrw }, + cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbx_getvar }, + cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL }, + cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbx_err }, + cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbx_dbg }; + +const struct cmdinfo *cmdinfo[MBX_CMD_MAX] = { + [MBX_CMD_DSP_WDSND] = &cif_wdsnd, + [MBX_CMD_DSP_WDREQ] = &cif_wdreq, + [MBX_CMD_DSP_BKSND] = &cif_bksnd, + [MBX_CMD_DSP_BKREQ] = &cif_bkreq, + [MBX_CMD_DSP_BKYLD] = &cif_bkyld, + [MBX_CMD_DSP_BKSNDP] = &cif_bksndp, + [MBX_CMD_DSP_BKREQP] = &cif_bkreqp, + [MBX_CMD_DSP_TCTL] = &cif_tctl, + [MBX_CMD_DSP_POLL] = &cif_poll, #ifdef OLD_BINARY_SUPPORT - /* v3.3 obsolete */ -/*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend, -#else -/*50*/ &cif_null, &cif_runlevel, &cif_pm, &cif_suspend, + [MBX_CMD_DSP_WDT] = &cif_wdt, /* v3.3 obsolete */ #endif - &cif_kfunc, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*60*/ &cif_tcfg, &cif_null, &cif_tadd, &cif_tdel, - &cif_null, &cif_tstop, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null, -/*70*/ &cif_dspcfg, &cif_null, &cif_regrw, &cif_null, - &cif_getvar, &cif_setvar, &cif_null, &cif_null, - &cif_err, &cif_dbg, &cif_null, &cif_null, - &cif_null, &cif_null, &cif_null, &cif_null + [MBX_CMD_DSP_RUNLEVEL] = &cif_runlevel, + [MBX_CMD_DSP_PM] = &cif_pm, + [MBX_CMD_DSP_SUSPEND] = &cif_suspend, + [MBX_CMD_DSP_KFUNC] = &cif_kfunc, + [MBX_CMD_DSP_TCFG] = &cif_tcfg, + [MBX_CMD_DSP_TADD] = &cif_tadd, + [MBX_CMD_DSP_TDEL] = &cif_tdel, + [MBX_CMD_DSP_TSTOP] = &cif_tstop, + [MBX_CMD_DSP_DSPCFG] = &cif_dspcfg, + [MBX_CMD_DSP_REGRW] = &cif_regrw, + [MBX_CMD_DSP_GETVAR] = &cif_getvar, + [MBX_CMD_DSP_SETVAR] = &cif_setvar, + [MBX_CMD_DSP_ERR] = &cif_err, + [MBX_CMD_DSP_DBG] = &cif_dbg, }; -int sync_with_dsp(unsigned short *syncwd, unsigned short tid, int try_cnt) +int sync_with_dsp(u16 *adr, u16 val, int try_cnt) { int try; - if (*(volatile unsigned short *)syncwd == tid) + if (*(volatile u16 *)adr == val) return 0; for (try = 0; try < try_cnt; try++) { udelay(1); - if (*(volatile unsigned short *)syncwd == tid) { + if (*(volatile u16 *)adr == val) { /* success! */ printk(KERN_INFO "omapdsp: sync_with_dsp(): try = %d\n", try); @@ -180,73 +150,11 @@ int sync_with_dsp(unsigned short *syncwd, unsigned short tid, int try_cnt) return -1; } -static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt) -{ - int cnt; - - local_irq_save(*flags); - if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0) - return 0; - /* - * mailbox is busy. wait for some usecs... - */ - local_irq_restore(*flags); - for (cnt = 0; cnt < try_cnt; cnt++) { - udelay(1); - local_irq_save(*flags); - if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0) /* success! */ - return 0; - local_irq_restore(*flags); - } - - /* fail! */ - return -1; -} - -#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE -#define print_mb_busy_abort(mb) \ - printk(KERN_DEBUG \ - "mbx: mailbox is busy. %s is aborting.\n", cmd_name(*mb)) -#define print_mb_mmu_abort(mb) \ - printk(KERN_DEBUG \ - "mbx: mmu interrupt is set. %s is aborting.\n", cmd_name(*mb)) -#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ -#define print_mb_busy_abort(mb) do {} while(0) -#define print_mb_mmu_abort(mb) do {} while(0) -#endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */ - -int __mbcmd_send(struct mbcmd *mb) -{ - struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; - unsigned long flags; - - /* - * DSP mailbox interrupt latency must be less than 1ms. - */ - if (mbsync_irq_save(&flags, 1000) < 0) { - print_mb_busy_abort(mb); - return -1; - } - - if (mbseq) { - mb->seq = mbseq->ad_arm; - mbseq->ad_arm++; - } else - mb->seq = 0; - mblog_add(mb, DIR_A2D); - mblog_printcmd(mb, DIR_A2D); - - omap_writew(mb_hw->data, MAILBOX_ARM2DSP1); - omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b); - - local_irq_restore(flags); - return 0; -} - /* - * __dsp_mbcmd_send(): mailbox dispatcher + * __dsp_mbcmd_send_exarg(): mailbox dispatcher */ -int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) +int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg, + int recovery_flag) { static DEFINE_MUTEX(mbsend_lock); int ret = 0; @@ -255,8 +163,10 @@ int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) * while MMU fault is set, * only recovery command can be executed */ - if (dsp_err_mmu_isset() && !recovery_flag) { - print_mb_mmu_abort(mb); + if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) { + printk(KERN_ERR + "mbx: mmu interrupt is set. %s is aborting.\n", + cmd_name(*mb)); return -1; } @@ -275,7 +185,7 @@ int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) * Therefore, we can call this function here safely. */ dsp_mem_enable(ipbuf_sys_ad); - if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) { + if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) { printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n"); dsp_mem_disable(ipbuf_sys_ad); ret = -EBUSY; @@ -288,15 +198,21 @@ int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) dsp_mem_disable(ipbuf_sys_ad); } - ret = __mbcmd_send(mb); + if (mbseq) + mbseq->ad_arm++; + + mblog_add(mb, DIR_A2D); + mblog_printcmd(mb, DIR_A2D); + + ret = mbx_send(mbx_dsp, *(mbx_msg_t *)mb); out: mutex_unlock(&mbsend_lock); return ret; } -int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg, - wait_queue_head_t *q) +int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg, + wait_queue_head_t *q) { long current_state; DECLARE_WAITQUEUE(wait, current); @@ -316,35 +232,47 @@ int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg, return 0; } -int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data, - int recovery_flag) +/* + * mbcmd receiver + */ +static void mbcmd_receiver(mbx_msg_t msg) { - struct mbcmd mb; + struct mbcmd *mb = (struct mbcmd *)&msg; + + if (cmdinfo[mb->cmd_h] == NULL) { + printk(KERN_ERR + "invalid message (%08x) for mbcmd_receiver().\n", msg); + return; + } + + (*mbseq_expect)++; + + mblog_add(mb, DIR_D2A); + mblog_printcmd(mb, DIR_D2A); - mbcmd_set(mb, cmdh, cmdl, data); - return __dsp_mbcmd_send(&mb, NULL, recovery_flag); + /* call handler for the command */ + if (cmdinfo[mb->cmd_h]->handler) + cmdinfo[mb->cmd_h]->handler(mb); + else + printk(KERN_ERR "mbx: %s is not allowed from DSP.\n", + cmd_name(*mb)); } static int mbsync_hold_mem_active; -void dsp_mb_start(void) +void dsp_mbx_start(void) { - mbx1_valid = 1; /* start interpreting */ + mbx_init_seq(mbx_dsp); mbseq_expect_tmp = 0; } -void dsp_mb_stop(void) +void dsp_mbx_stop(void) { - mbx1_valid = 0; /* stop interpreting */ - if (mbsync_hold_mem_active) { - dsp_mem_disable((void *)daram_base); - mbsync_hold_mem_active = 0; - } mbseq = NULL; mbseq_expect = &mbseq_expect_tmp; } -int dsp_mb_config(void *p) +int dsp_mbx_config(void *p) { unsigned long flags; @@ -372,106 +300,76 @@ int dsp_mb_config(void *p) return 0; } -/* - * mbq: mailbox queue - */ -#define MBQ_DEPTH 16 -struct mbq { - struct mbcmd mb[MBQ_DEPTH]; - int rp, wp, full; -} mbq = { - .rp = 0, - .wp = 0, -}; +static int __init dsp_mbx_init(void) +{ + int i; + int ret; -#define mbq_inc(p) do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0) + for (i = 0; i < MBX_CMD_MAX; i++) { + if (cmdinfo[i] != NULL) { + ret = register_mbx_receiver(mbx_dsp, i, mbcmd_receiver); + if (ret) + goto fail; + } + } -/* - * workqueue for mbx1 - */ -static void do_mbx1(void) -{ - int empty = 0; + return 0; - disable_irq(INT_D2A_MB1); - if ((mbq.rp == mbq.wp) && !mbq.full) - empty = 1; - enable_irq(INT_D2A_MB1); +fail: + for (i--; i; i--) + unregister_mbx_receiver(mbx_dsp, i, mbcmd_receiver); - while (!empty) { - struct mbcmd *mb; + return ret; +} - mb = &mbq.mb[mbq.rp]; +static void dsp_mbx_exit(void) +{ + int i; - mblog_add(mb, DIR_D2A); - mblog_printcmd(mb, DIR_D2A); + for (i = 0; i < MBX_CMD_MAX; i++) { + if (cmdinfo[i] != NULL) + unregister_mbx_receiver(mbx_dsp, i, mbcmd_receiver); + } - /* - * call handler for each command - */ - if (cmdinfo[mb->cmd_h]->handler) - cmdinfo[mb->cmd_h]->handler(mb); - else if (cmdinfo[mb->cmd_h] != &cif_null) - printk(KERN_ERR "mbx: %s is not allowed from DSP.\n", - cmd_name(*mb)); - else - printk(KERN_ERR - "mbx: Unrecognized command: " - "cmd=0x%04x, data=0x%04x\n", - ((struct mbcmd_hw *)mb)->cmd & 0x7fff, mb->data); - - disable_irq(INT_D2A_MB1); - mbq_inc(mbq.rp); - if (mbq.rp == mbq.wp) - empty = 1; - /* if mbq has been full, now we have a room. */ - if (mbq.full) { - mbq.full = 0; - enable_irq(INT_D2A_MB1); - } - enable_irq(INT_D2A_MB1); + if (mbsync_hold_mem_active) { + dsp_mem_disable((void *)daram_base); + mbsync_hold_mem_active = 0; } } -static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL); - /* * kernel function dispatcher */ -extern void mbx1_fbctl_upd(void); -extern void mbx1_fbctl_disable(void); +extern void mbx_fbctl_upd(void); +extern void mbx_fbctl_disable(struct mbcmd *mb); -static void mbx1_kfunc_fbctl(unsigned short data) +static void mbx_kfunc_fbctl(struct mbcmd *mb) { - switch (data) { - case OMAP_DSP_MBCMD_FBCTL_UPD: - mbx1_fbctl_upd(); + switch (mb->data) { + case FBCTL_UPD: + mbx_fbctl_upd(); break; - case OMAP_DSP_MBCMD_FBCTL_DISABLE: - mbx1_fbctl_disable(); + case FBCTL_DISABLE: + mbx_fbctl_disable(mb); break; default: printk(KERN_ERR - "mailbox: Unknown FBCTL from DSP: 0x%04x\n", data); + "mbx: Unknown FBCTL from DSP: 0x%04x\n", mb->data); } } -static void mbx1_kfunc_audio_pwr(unsigned short data) +static void mbx_kfunc_audio_pwr(unsigned short data) { - struct mbcmd mb; - switch (data) { - case OMAP_DSP_MBCMD_AUDIO_PWR_UP: + case AUDIO_PWR_UP: omap_dsp_audio_pwr_up_request(0); /* send back ack */ - mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR, - OMAP_DSP_MBCMD_AUDIO_PWR_UP); - dsp_mbcmd_send(&mb); + mbcompose_send(KFUNC, KFUNC_AUDIO_PWR, AUDIO_PWR_UP); break; - case OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1: + case AUDIO_PWR_DOWN1: omap_dsp_audio_pwr_down_request(1); break; - case OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2: + case AUDIO_PWR_DOWN2: omap_dsp_audio_pwr_down_request(2); break; default: @@ -480,118 +378,21 @@ static void mbx1_kfunc_audio_pwr(unsigned short data) } } -static void mbx1_kfunc(struct mbcmd *mb) +static void mbx_kfunc(struct mbcmd *mb) { switch (mb->cmd_l) { - case OMAP_DSP_MBCMD_KFUNC_FBCTL: - mbx1_kfunc_fbctl(mb->data); + case KFUNC_FBCTL: + mbx_kfunc_fbctl(mb); break; - case OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR: - mbx1_kfunc_audio_pwr(mb->data); + case KFUNC_AUDIO_PWR: + mbx_kfunc_audio_pwr(mb->data); break; default: printk(KERN_ERR - "mailbox: Unknown kfunc from DSP: 0x%02x\n", mb->cmd_l); - } -} - -/* - * mailbox interrupt handler - */ -static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - union { - struct mbcmd sw; - struct mbcmd_hw hw; - } *mb = (void *)&mbq.mb[mbq.wp]; - -#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) - mb->hw.data = omap_readw(MAILBOX_DSP2ARM1); - mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM1b); -#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2) - mb->hw.data = omap_readw(MAILBOX_DSP2ARM2); - mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM2b); -#endif - - /* if mbx1 has not been validated yet, discard. */ - if (!mbx1_valid) - return IRQ_HANDLED; - - if (mb->sw.seq != (*mbseq_expect & 1)) { - switch (mbseq_check_level) { - case MBSEQ_CHECK_NONE: - break; - case MBSEQ_CHECK_VERBOSE: - printk(KERN_INFO - "mbx: illegal seq bit!!! ignoring this command." - " (%04x:%04x)\n", mb->hw.cmd, mb->hw.data); - return IRQ_HANDLED; - case MBSEQ_CHECK_SILENT: - return IRQ_HANDLED; - } - } - - (*mbseq_expect)++; - - mbq_inc(mbq.wp); - if (mbq.wp == mbq.rp) { /* mbq is full */ - mbq.full = 1; - disable_irq(INT_D2A_MB1); + "mbx: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l); } - schedule_work(&mbx1_work); - - return IRQ_HANDLED; } -static irqreturn_t mbx2_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned short cmd, data; - -#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) - data = omap_readw(MAILBOX_DSP2ARM2); - cmd = omap_readw(MAILBOX_DSP2ARM2b); -#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2) - data = omap_readw(MAILBOX_DSP2ARM1); - cmd = omap_readw(MAILBOX_DSP2ARM1b); -#endif - printk(KERN_DEBUG - "mailbox2 interrupt! cmd=%04x, data=%04x\n", cmd, data); - - return IRQ_HANDLED; -} - -#if 0 -static void mpuio_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - printk(KERN_INFO "MPUIO interrupt!\n"); -} -#endif - -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *procdir_dsp = NULL; - -static void dsp_create_procdir_dsp(void) -{ - procdir_dsp = proc_mkdir("dsp", 0); - if (procdir_dsp == NULL) { - printk(KERN_ERR - "omapdsp: failed to register proc directory: dsp\n"); - } -} - -static void dsp_remove_procdir_dsp(void) -{ - procdir_dsp = NULL; - remove_proc_entry("dsp", 0); -} -#else /* CONFIG_PROC_FS */ -#define dsp_create_procdir_dsp() do { } while (0) -#define dsp_remove_procdir_dsp() do { } while (0) -#endif /* CONFIG_PROC_FS */ - -extern irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, - struct pt_regs *regs); - extern int dsp_ctl_core_init(void); extern void dsp_ctl_core_exit(void); extern void dsp_ctl_init(void); @@ -613,21 +414,16 @@ static void dsp_dev_release(struct device *dev) /* * driver functions */ -#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) -# define INT_D2A_MB2 INT_DSP_MAILBOX2 -#elif(INT_D2A_MB1 == INT_DSP_MAILBOX2) /* swap MB1 and MB2 */ -# define INT_D2A_MB2 INT_DSP_MAILBOX1 -#endif - static int __init dsp_drv_probe(struct platform_device *pdev) { int ret; printk(KERN_INFO "OMAP DSP driver initialization\n"); - - //__dsp_enable(); // XXX - - dsp_create_procdir_dsp(); +#ifdef CONFIG_ARCH_OMAP2 + clk_enable(dsp_fck_handle); + clk_enable(dsp_ick_handle); + __dsp_per_enable(); +#endif if ((ret = dsp_ctl_core_init()) < 0) goto fail1; @@ -637,52 +433,11 @@ static int __init dsp_drv_probe(struct platform_device *pdev) mblog_init(); if ((ret = dsp_taskmod_init()) < 0) goto fail3; - - /* - * mailbox interrupt handlers registration - */ - ret = request_irq(INT_D2A_MB1, mbx1_interrupt, SA_INTERRUPT, "dsp", - &pdev->dev); - if (ret) { - printk(KERN_ERR - "failed to register mailbox1 interrupt: %d\n", ret); + if ((ret = dsp_mbx_init()) < 0) goto fail4; - } - - ret = request_irq(INT_D2A_MB2, mbx2_interrupt, SA_INTERRUPT, "dsp", - &pdev->dev); - if (ret) { - printk(KERN_ERR - "failed to register mailbox2 interrupt: %d\n", ret); - goto fail5; - } - - ret = request_irq(INT_DSP_MMU, dsp_mmu_interrupt, SA_INTERRUPT, "dsp", - &pdev->dev); - if (ret) { - printk(KERN_ERR - "failed to register DSP MMU interrupt: %d\n", ret); - goto fail6; - } - - /* MMU interrupt is not enabled until DSP runs */ - disable_irq(INT_DSP_MMU); - -#if 0 - ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev); - if (ret) { - printk(KERN_ERR - "failed to register MPUIO interrupt: %d\n", ret); - goto fail7; - } -#endif return 0; -fail6: - free_irq(INT_D2A_MB2, &pdev->dev); -fail5: - free_irq(INT_D2A_MB1, &pdev->dev); fail4: dsp_taskmod_exit(); fail3: @@ -692,9 +447,11 @@ fail3: fail2: dsp_ctl_core_exit(); fail1: - dsp_remove_procdir_dsp(); - - //__dsp_disable(); // XXX +#ifdef CONFIG_ARCH_OMAP2 + __dsp_per_disable(); + clk_disable(dsp_ick_handle); + clk_disable(dsp_fck_handle); +#endif return ret; } @@ -702,41 +459,34 @@ static int dsp_drv_remove(struct platform_device *pdev) { dsp_cpustat_request(CPUSTAT_RESET); -#if 0 - free_irq(INT_MPUIO, dev); -#endif - free_irq(INT_DSP_MMU, &pdev->dev); - free_irq(INT_D2A_MB2, &pdev->dev); - free_irq(INT_D2A_MB1, &pdev->dev); - - /* recover disable_depth */ - enable_irq(INT_DSP_MMU); - - dspuncfg(); + dsp_cfgstat_request(CFGSTAT_CLEAN); + dsp_mbx_exit(); dsp_taskmod_exit(); mblog_exit(); dsp_ctl_exit(); dsp_mem_exit(); dsp_ctl_core_exit(); - dsp_remove_procdir_dsp(); - - //__dsp_disable(); // XXX +#ifdef CONFIG_ARCH_OMAP2 + __dsp_per_disable(); + clk_disable(dsp_ick_handle); + clk_disable(dsp_fck_handle); +#endif return 0; } #ifdef CONFIG_PM static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state) { - dsp_suspend(); + dsp_cfgstat_request(CFGSTAT_SUSPEND); return 0; } static int dsp_drv_resume(struct platform_device *pdev) { - dsp_resume(); + dsp_cfgstat_request(CFGSTAT_RESUME); return 0; } @@ -746,14 +496,6 @@ static int dsp_drv_resume(struct platform_device *pdev) #endif /* CONFIG_PM */ static struct resource dsp_resources[] = { - { - .start = INT_DSP_MAILBOX1, - .flags = IORESOURCE_IRQ, - }, - { - .start = INT_DSP_MAILBOX2, - .flags = IORESOURCE_IRQ, - }, { .start = INT_DSP_MMU, .flags = IORESOURCE_IRQ, @@ -784,6 +526,12 @@ static int __init omap_dsp_mod_init(void) { int ret; + mbx_dsp = mbx_get("DSP"); + if (IS_ERR(mbx_dsp)) { + printk(KERN_ERR "failed to get mailbox handler for DSP.\n"); + goto fail1; + } + ret = platform_device_register(&dsp_device); if (ret) { printk(KERN_ERR "failed to register the DSP device: %d\n", ret); diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c index 3fab9489c97..4323150b1d8 100644 --- a/arch/arm/plat-omap/dsp/dsp_ctl.c +++ b/arch/arm/plat-omap/dsp/dsp_ctl.c @@ -1,35 +1,29 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_ctl.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP control device driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/09: DSP Gateway version 3.3 */ #include -#include -#include #include #include -#include #include #include #include @@ -39,123 +33,199 @@ #include #include #include -#include +#include #include "hardware_dsp.h" +#include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" +#include "ioctl.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 mbx_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); -static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo); -extern struct device_attribute dev_attr_ipbuf; - -static enum cfgstat { - CFG_ERR, - CFG_READY, - CFG_SUSPEND -} cfgstat; -int mbx_revision; -static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q); -static unsigned short ioctl_wait_cmd; -static DEFINE_MUTEX(ioctl_lock); -static unsigned char n_stask; +#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); /* - * control functions + * misc interactive mailbox command operations */ -static short varread_val[5]; /* maximum */ +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 dsp_regread(unsigned short cmd_l, unsigned short adr, - unsigned short *val) +static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data, + u16 *retvp) { - struct mbcmd mb; + struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data); int ret = 0; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&misc_mb_wait.lock)) + return -EINTR; - ioctl_wait_cmd = MBCMD(REGRW); - mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); + 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 (ioctl_wait_cmd != 0) { - printk(KERN_ERR "omapdsp: register read error!\n"); + if (misc_mb_wait.cmd_h != 0) ret = -EINVAL; - goto up_out; + + 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(MBX_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 + "mbx: unexpected command %s received!\n", cmdstr); + return -1; + } + + /* + * if argc == 1, receive data through mbx: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 "mbx: %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 "mbx: %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); } - *val = varread_val[0]; + 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"); -up_out: - mutex_unlock(&ioctl_lock); return ret; } -static int dsp_regwrite(unsigned short cmd_l, unsigned short adr, - unsigned short val) +static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val) { - struct mbcmd mb; + u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW; struct mb_exarg arg = { - .tid = OMAP_DSP_TID_ANON, + .tid = TID_ANON, .argc = 1, .argv = &val, }; - mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); - dsp_mbcmd_send_exarg(&mb, &arg); + mbcompose_send_exarg(REGRW, cmd_l, adr, &arg); return 0; } -static int dsp_getvar(unsigned char varid, unsigned short *val, int sz) +static int dsp_getvar(u8 varid, u16 *val) { - struct mbcmd mb; - int ret = 0; - - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; - - ioctl_wait_cmd = MBCMD(GETVAR); - mbcmd_set(mb, MBCMD(GETVAR), varid, 0); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); + int ret; - if (ioctl_wait_cmd != 0) { + ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val); + if ((ret < 0) && (ret != -EINTR)) printk(KERN_ERR "omapdsp: variable read error!\n"); - ret = -EINVAL; - goto up_out; - } - - memcpy(val, varread_val, sz * sizeof(short)); -up_out: - mutex_unlock(&ioctl_lock); return ret; } -static int dsp_setvar(unsigned char varid, unsigned short val) +static int dsp_setvar(u8 varid, u16 val) { - dsp_mbsend(MBCMD(SETVAR), varid, val); + mbcompose_send(SETVAR, varid, val); return 0; } -static int dspcfg(void) +/* + * dsp_cfg() return value + * = 0: OK + * = 1: failed, but state is clear. (DSPCFG command failed) + * < 0: failed. need cleanup. + */ +static int dsp_cfg(void) { - struct mbcmd mb; int ret = 0; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; - - if (cfgstat != CFG_ERR) { - printk(KERN_ERR - "omapdsp: DSP has been already configured. " - "do unconfig!\n"); - ret = -EBUSY; - goto up_out; - } - +#ifdef CONFIG_ARCH_OMAP1 /* for safety */ dsp_mem_usecount_clear(); +#endif /* * DSPCFG command and dsp_mem_start() must be called @@ -163,215 +233,270 @@ static int dspcfg(void) */ dsp_mem_enable((void *)dspmem_base); - dsp_mb_start(); + dsp_mbx_start(); dsp_twch_start(); dsp_mem_start(); dsp_err_start(); mbx_revision = -1; - ioctl_wait_cmd = MBCMD(DSPCFG); - mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); - if (ioctl_wait_cmd != 0) { - printk(KERN_ERR "omapdsp: configuration error!\n"); - ret = -EINVAL; - cfgstat = CFG_ERR; - goto up_out; + 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; } -#ifdef OLD_BINARY_SUPPORT +#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 ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) { - ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE, - DSPREG_ICR_DMA_IDLE_DOMAIN); + if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0) + goto out; } #endif - if ((ret = dsp_task_config_all(n_stask)) < 0) { - mutex_unlock(&ioctl_lock); - dspuncfg(); - dsp_mem_disable((void *)dspmem_base); - return -EINVAL; - } + if ((ret = dsp_task_config_all(n_stask)) < 0) + goto out; - cfgstat = CFG_READY; + /* initialization */ +#ifdef CONFIG_OMAP_DSP_FBEXPORT + fbstat = FBSTAT_ENABLED; +#endif /* send parameter */ - if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, - dsp_cpustat_get_icrmask())) < 0) - goto up_out; + if ((ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask())) < 0) + goto out; /* create runtime sysfs entries */ device_create_file(&dsp_device.dev, &dev_attr_loadinfo); - device_create_file(&dsp_device.dev, &dev_attr_ipbuf); -up_out: +out: dsp_mem_disable((void *)dspmem_base); - mutex_unlock(&ioctl_lock); return ret; } -int dspuncfg(void) +static int dsp_uncfg(void) { if (dsp_taskmod_busy()) { printk(KERN_WARNING "omapdsp: tasks are busy.\n"); return -EBUSY; } - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; - /* FIXME: lock task module */ /* remove runtime sysfs entries */ device_remove_file(&dsp_device.dev, &dev_attr_loadinfo); - device_remove_file(&dsp_device.dev, &dev_attr_ipbuf); - dsp_mb_stop(); + dsp_mbx_stop(); dsp_twch_stop(); dsp_mem_stop(); dsp_err_stop(); dsp_dbg_stop(); dsp_task_unconfig_all(); ipbuf_stop(); - cfgstat = CFG_ERR; - mutex_unlock(&ioctl_lock); return 0; } -int dsp_is_ready(void) +static int dsp_suspend(void) { - return (cfgstat == CFG_READY) ? 1 : 0; + 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; } -/* - * polls all tasks - */ -int dsp_poll(void) +int dsp_cfgstat_request(enum cfgstat_e st_req) { - struct mbcmd mb; - int ret = 0; + static DEFINE_MUTEX(cfgstat_lock); + int ret = 0, ret_override = 0; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&cfgstat_lock)) + return -EINTR; - ioctl_wait_cmd = MBCMD(POLL); - mbcmd_set(mb, MBCMD(POLL), 0, 0); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); +again: + switch (st_req) { - if (ioctl_wait_cmd != 0) { - printk(KERN_ERR "omapdsp: poll error!\n"); - ret = -EINVAL; - goto up_out; - } + /* cfgstat takes CLEAN, READY or SUSPEND, + while st_req can take SUSPEND in addition. */ -up_out: - mutex_unlock(&ioctl_lock); - return ret; -} + case CFGSTAT_CLEAN: + if (cfgstat == CFGSTAT_CLEAN) + goto up_out; + if ((ret = dsp_uncfg()) < 0) + goto up_out; + break; -void dsp_runlevel(unsigned char level) -{ - if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY) - dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0); - else - dsp_mbsend(MBCMD(RUNLEVEL), level, 0); -} + case CFGSTAT_READY: + if (cfgstat != CFGSTAT_CLEAN) { + printk(KERN_ERR "omapdsp: DSP is ready already!\n"); + ret = -EINVAL; + goto up_out; + } -static enum cfgstat cfgstat_save_suspend; + 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; -/* - * suspend / resume callbacks - * DSP is not reset within this code, but done in omap_pm_suspend. - * so if these functions are called as OMAP_DSP_IOCTL_SUSPEND, - * DSP should be reset / unreset out of these functions. - */ -int dsp_suspend(void) -{ - struct mbcmd mb; - int ret = 0; + case CFGSTAT_READY: + if ((ret = dsp_suspend()) < 0) + goto up_out; + break; - if (cfgstat == CFG_SUSPEND) { - printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n"); - return -EINVAL; - } + case CFGSTAT_SUSPEND: + goto up_out; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; + default: + BUG(); - cfgstat_save_suspend = cfgstat; - if (!dsp_is_ready()) { - if (dsp_cpustat_get_stat() == CPUSTAT_RUN) { - printk(KERN_WARNING - "omapdsp: illegal operation: trying suspend DSP " - "while it is running but has not configured " - "yet.\n" - " Resetting DSP...\n"); } - goto transition; - } - ioctl_wait_cmd = MBCMD(SUSPEND); - mbcmd_set(mb, MBCMD(SUSPEND), 0, 0); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); + 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(); - if (ioctl_wait_cmd != 0) { - printk(KERN_ERR "omapdsp: DSP suspend error!\n"); - ret = -EINVAL; - goto up_out; } - udelay(100); -transition: - cfgstat = CFG_SUSPEND; + cfgstat = st_req; up_out: - mutex_unlock(&ioctl_lock); + 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_resume(void) +int dsp_set_runlevel(u8 level) { - if (cfgstat != CFG_SUSPEND) { - printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n"); - return -EINVAL; + 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; } - cfgstat = cfgstat_save_suspend; return 0; } +#ifdef CONFIG_OMAP_DSP_FBEXPORT static void dsp_fbctl_enable(void) { - dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, - OMAP_DSP_MBCMD_FBCTL_ENABLE); + 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; - struct mbcmd mb; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&fbstat_lock)) + return -EINTR; - ioctl_wait_cmd = MBCMD(KFUNC); - mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, - OMAP_DSP_MBCMD_FBCTL_DISABLE); - dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q); - if (ioctl_wait_cmd != 0) { - printk(KERN_ERR "omapdsp: fb disable error!\n"); - ret = -EINVAL; + 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(); } - mutex_unlock(&ioctl_lock); - return ret; + fbstat = st; +up_out: + mutex_unlock(&fbstat_lock); + return 0; } +#endif /* CONFIG_OMAP_DSP_FBEXPORT */ /* * DSP control device file operations @@ -385,55 +510,60 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, /* * command level 1: commands which don't need lock */ - case OMAP_DSP_IOCTL_RUN: + case DSPCTL_IOCTL_RUN: dsp_cpustat_request(CPUSTAT_RUN); break; - case OMAP_DSP_IOCTL_RESET: + case DSPCTL_IOCTL_RESET: dsp_cpustat_request(CPUSTAT_RESET); break; - case OMAP_DSP_IOCTL_SETRSTVECT: - ret = dsp_set_rstvect((unsigned long)arg); + case DSPCTL_IOCTL_SETRSTVECT: + ret = dsp_set_rstvect((dsp_long_t)arg); break; - case OMAP_DSP_IOCTL_CPU_IDLE: +#ifdef CONFIG_ARCH_OMAP1 + case DSPCTL_IOCTL_CPU_IDLE: dsp_cpustat_request(CPUSTAT_CPU_IDLE); break; - case OMAP_DSP_IOCTL_GBL_IDLE: + case DSPCTL_IOCTL_GBL_IDLE: dsp_cpustat_request(CPUSTAT_GBL_IDLE); break; - case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON: + case DSPCTL_IOCTL_MPUI_WORDSWAP_ON: mpui_wordswap_on(); break; - case OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF: + case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF: mpui_wordswap_off(); break; - case OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON: + case DSPCTL_IOCTL_MPUI_BYTESWAP_ON: mpui_byteswap_on(); break; - case OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF: + case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF: mpui_byteswap_off(); break; +#endif /* CONFIG_ARCH_OMAP1 */ + + case DSPCTL_IOCTL_TASKCNT: + ret = dsp_task_count(); + break; - case OMAP_DSP_IOCTL_MBSEND: + case DSPCTL_IOCTL_MBSEND: { struct omap_dsp_mailbox_cmd u_cmd; - struct mbcmd_hw mb; + mbx_msg_t msg; if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd))) return -EFAULT; - mb.cmd = u_cmd.cmd; - mb.data = u_cmd.data; - ret = dsp_mbcmd_send((struct mbcmd *)&mb); + msg = (u_cmd.cmd << 16) | u_cmd.data; + ret = dsp_mbcmd_send((struct mbcmd *)&msg); break; } - case OMAP_DSP_IOCTL_SETVAR: + case DSPCTL_IOCTL_SETVAR: { struct omap_dsp_varinfo var; if (copy_from_user(&var, (void *)arg, sizeof(var))) @@ -442,126 +572,119 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, break; } - case OMAP_DSP_IOCTL_RUNLEVEL: - dsp_runlevel(arg); + case DSPCTL_IOCTL_RUNLEVEL: + ret = dsp_set_runlevel(arg); break; - case OMAP_DSP_IOCTL_FBEN: - dsp_fbctl_enable(); - return 0; +#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 OMAP_DSP_IOCTL_DSPCFG: - ret = dspcfg(); + case DSPCTL_IOCTL_DSPCFG: + ret = dsp_cfgstat_request(CFGSTAT_READY); break; - case OMAP_DSP_IOCTL_DSPUNCFG: - ret = dspuncfg(); + case DSPCTL_IOCTL_DSPUNCFG: + ret = dsp_cfgstat_request(CFGSTAT_CLEAN); break; - case OMAP_DSP_IOCTL_TASKCNT: - ret = dsp_task_count(); - break; - - case OMAP_DSP_IOCTL_POLL: + case DSPCTL_IOCTL_POLL: ret = dsp_poll(); break; - case OMAP_DSP_IOCTL_FBDIS: - ret = dsp_fbctl_disable(); +#ifdef CONFIG_OMAP_DSP_FBEXPORT + case DSPCTL_IOCTL_FBDIS: + ret = dsp_fbstat_request(FBSTAT_DISABLED); break; +#endif - /* - * FIXME: cpu status control for suspend - resume - */ - case OMAP_DSP_IOCTL_SUSPEND: - if ((ret = dsp_suspend()) < 0) + case DSPCTL_IOCTL_SUSPEND: + if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0) break; dsp_cpustat_request(CPUSTAT_RESET); break; - case OMAP_DSP_IOCTL_RESUME: - if ((ret = dsp_resume()) < 0) + case DSPCTL_IOCTL_RESUME: + if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0) break; dsp_cpustat_request(CPUSTAT_RUN); break; - case OMAP_DSP_IOCTL_REGMEMR: + case DSPCTL_IOCTL_REGMEMR: { struct omap_dsp_reginfo *u_reg = (void *)arg; - unsigned short adr, val; + u16 adr, val; - if (copy_from_user(&adr, &u_reg->adr, sizeof(short))) + if (copy_from_user(&adr, &u_reg->adr, sizeof(u16))) return -EFAULT; - if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_MEMR, - adr, &val)) < 0) + if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0) return ret; - if (copy_to_user(&u_reg->val, &val, sizeof(short))) + if (copy_to_user(&u_reg->val, &val, sizeof(u16))) return -EFAULT; break; } - case OMAP_DSP_IOCTL_REGMEMW: + case DSPCTL_IOCTL_REGMEMW: { struct omap_dsp_reginfo reg; if (copy_from_user(®, (void *)arg, sizeof(reg))) return -EFAULT; - ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_MEMW, - reg.adr, reg.val); + ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val); break; } - case OMAP_DSP_IOCTL_REGIOR: + case DSPCTL_IOCTL_REGIOR: { struct omap_dsp_reginfo *u_reg = (void *)arg; - unsigned short adr, val; + u16 adr, val; - if (copy_from_user(&adr, &u_reg->adr, sizeof(short))) + if (copy_from_user(&adr, &u_reg->adr, sizeof(u16))) return -EFAULT; - if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_IOR, - adr, &val)) < 0) + if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0) return ret; - if (copy_to_user(&u_reg->val, &val, sizeof(short))) + if (copy_to_user(&u_reg->val, &val, sizeof(u16))) return -EFAULT; break; } - case OMAP_DSP_IOCTL_REGIOW: + case DSPCTL_IOCTL_REGIOW: { struct omap_dsp_reginfo reg; if (copy_from_user(®, (void *)arg, sizeof(reg))) return -EFAULT; - ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_IOW, - reg.adr, reg.val); + ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val); break; } - case OMAP_DSP_IOCTL_GETVAR: + case DSPCTL_IOCTL_GETVAR: { struct omap_dsp_varinfo *u_var = (void *)arg; - unsigned char varid; - unsigned short val[5]; /* maximum */ + u8 varid; + u16 val[5]; /* maximum */ int argc; - if (copy_from_user(&varid, &u_var->varid, sizeof(char))) + if (copy_from_user(&varid, &u_var->varid, sizeof(u8))) return -EFAULT; switch (varid) { - case OMAP_DSP_MBCMD_VARID_ICRMASK: + case VARID_ICRMASK: argc = 1; break; - case OMAP_DSP_MBCMD_VARID_LOADINFO: + case VARID_LOADINFO: argc = 5; break; default: return -EINVAL; } - if ((ret = dsp_getvar(varid, val, argc)) < 0) + if ((ret = dsp_getvar(varid, val)) < 0) return ret; - if (copy_to_user(&u_var->val, val, sizeof(short) * argc)) + if (copy_to_user(&u_var->val, val, sizeof(u16) * argc)) return -EFAULT; break; } @@ -574,40 +697,31 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, } /* - * functions called from mailbox1 interrupt routine + * functions called from mailbox interrupt routine */ -void mbx1_suspend(struct mbcmd *mb) +void mbx_suspend(struct mbcmd *mb) +{ + misc_mbcmd_response(mb, 0, 0); +} + +void mbx_dspcfg(struct mbcmd *mb) { - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(SUSPEND))) { + 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 != MBX_CMD_DSP_DSPCFG)) { printk(KERN_WARNING - "mbx: SUSPEND command received, " + "mbx: DSPCFG command received, " "but nobody is waiting for it...\n"); return; } - ioctl_wait_cmd = 0; - wake_up_interruptible(&ioctl_wait_q); -} - -void mbx1_dspcfg(struct mbcmd *mb) -{ - unsigned char last = mb->cmd_l & 0x80; - unsigned char cfgcmd = mb->cmd_l & 0x7f; - static unsigned long tmp_ipb_adr; - /* mailbox protocol check */ - if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) { - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(DSPCFG))) { - printk(KERN_WARNING - "mbx: DSPCFG command received, " - "but nobody is waiting for it...\n"); - return; - } - + if (cfgcmd == DSPCFG_PROTREV) { mbx_revision = mb->data; - if (mbx_revision == OMAP_DSP_MBPROT_REVISION) + if (mbx_revision == MBPROT_REVISION) return; #ifdef OLD_BINARY_SUPPORT else if ((mbx_revision == MBREV_3_0) || @@ -622,7 +736,7 @@ void mbx1_dspcfg(struct mbcmd *mb) printk(KERN_ERR "mbx: protocol revision check error!\n" " expected=0x%04x, received=0x%04x\n", - OMAP_DSP_MBPROT_REVISION, mb->data); + MBPROT_REVISION, mb->data); mbx_revision = -1; goto abort1; } @@ -639,24 +753,16 @@ void mbx1_dspcfg(struct mbcmd *mb) return; } - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(DSPCFG))) { - printk(KERN_WARNING - "mbx: DSPCFG command received, " - "but nobody is waiting for it...\n"); - return; - } - switch (cfgcmd) { - case OMAP_DSP_MBCMD_DSPCFG_SYSADRH: - tmp_ipb_adr = (unsigned long)mb->data << 16; + case DSPCFG_SYSADRH: + tmp_ipb_adr = (u32)mb->data << 16; break; - case OMAP_DSP_MBCMD_DSPCFG_SYSADRL: + case DSPCFG_SYSADRL: tmp_ipb_adr |= mb->data; break; - case OMAP_DSP_MBCMD_DSPCFG_ABORT: + case DSPCFG_ABORT: goto abort1; default: @@ -668,21 +774,26 @@ void mbx1_dspcfg(struct mbcmd *mb) if (last) { void *badr; - unsigned short bln; - unsigned short bsz; - volatile unsigned short *buf; + u16 bln; + u16 bsz; + volatile u16 *buf; void *ipb_sys_da, *ipb_sys_ad; - void *mbseq; + void *mbseq; /* FIXME: 3.4 obsolete */ short *dbg_buf; - unsigned short dbg_buf_sz, dbg_line_sz; + 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 (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { + if (dsp_mem_enable(ipbuf_sys_da) < 0) { + printk(KERN_ERR "mbx: DSPCFG - ipbuf_sys_da read failed!\n"); + goto abort1; + } + if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) { printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n"); + dsp_mem_disable(ipbuf_sys_da); goto abort1; } /* @@ -690,7 +801,7 @@ void mbx1_dspcfg(struct mbcmd *mb) * we must read with 16bit-access */ #ifdef OLD_BINARY_SUPPORT - if (mbx_revision == OMAP_DSP_MBPROT_REVISION) { + if (mbx_revision == MBPROT_REVISION) { #endif buf = ipbuf_sys_da->d; n_stask = buf[0]; @@ -735,11 +846,14 @@ void mbx1_dspcfg(struct mbcmd *mb) dbg_buf_sz = 0; dbg_line_sz = 0; mem_syncp = NULL; - } else /* should not occur */ + } 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 @@ -749,56 +863,36 @@ void mbx1_dspcfg(struct mbcmd *mb) goto abort1; if (ipbuf_config(bln, bsz, badr) < 0) goto abort1; - if (dsp_mb_config(mbseq) < 0) + if (dsp_mbx_config(mbseq) < 0) goto abort2; if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0) goto abort2; if (dsp_mem_sync_config(mem_syncp) < 0) goto abort2; - ioctl_wait_cmd = 0; - wake_up_interruptible(&ioctl_wait_q); + misc_mb_wait.cmd_h = 0; + wake_up_interruptible(&misc_mb_wait.wait_q); } return; abort2: ipbuf_stop(); abort1: - wake_up_interruptible(&ioctl_wait_q); + wake_up_interruptible(&misc_mb_wait.wait_q); return; } -void mbx1_poll(struct mbcmd *mb) +void mbx_poll(struct mbcmd *mb) { - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(POLL))) { - printk(KERN_WARNING - "mbx: POLL command received, " - "but nobody is waiting for it...\n"); - return; - } - - ioctl_wait_cmd = 0; - wake_up_interruptible(&ioctl_wait_q); + misc_mbcmd_response(mb, 0, 0); } -void mbx1_regrw(struct mbcmd *mb) +void mbx_regrw(struct mbcmd *mb) { - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(REGRW))) { - printk(KERN_WARNING - "mbx: REGRW command received, " - "but nobody is waiting for it...\n"); - return; - } - switch (mb->cmd_l) { - case OMAP_DSP_MBCMD_REGRW_DATA: - ioctl_wait_cmd = 0; - varread_val[0] = mb->data; - wake_up_interruptible(&ioctl_wait_q); - return; - + case REGRW_DATA: + misc_mbcmd_response(mb, 1, 0); + break; default: printk(KERN_ERR "mbx: Illegal REGRW command: " @@ -807,49 +901,38 @@ void mbx1_regrw(struct mbcmd *mb) } } -void mbx1_getvar(struct mbcmd *mb) +void mbx_getvar(struct mbcmd *mb) { - unsigned char varid = mb->cmd_l; - int i; - volatile unsigned short *buf; - - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(GETVAR))) { - printk(KERN_WARNING - "mbx: GETVAR command received, " - "but nobody is waiting for it...\n"); - return; - } - - ioctl_wait_cmd = 0; - switch (varid) { - case OMAP_DSP_MBCMD_VARID_ICRMASK: - varread_val[0] = mb->data; + switch (mb->cmd_l) { + case VARID_ICRMASK: + misc_mbcmd_response(mb, 1, 1); break; - case OMAP_DSP_MBCMD_VARID_LOADINFO: - { - if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { - printk(KERN_ERR - "mbx: GETVAR - IPBUF sync failed!\n"); - return; - } - /* need word access. do not use memcpy. */ - buf = ipbuf_sys_da->d; - for (i = 0; i < 5; i++) { - varread_val[i] = buf[i]; - } - release_ipbuf_pvt(ipbuf_sys_da); - break; - } + case VARID_LOADINFO: + misc_mbcmd_response(mb, 5, 1); + break; + default: + printk(KERN_ERR + "mbx: Illegal GETVAR command: " + "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data); + return; } - wake_up_interruptible(&ioctl_wait_q); +} - return; +void mbx_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) { @@ -861,9 +944,9 @@ static ssize_t ifver_show(struct device *dev, struct device_attribute *attr, * 3.2: sysfs / udev support * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device * 3.3: added following ioctls - * OMAP_DSP_IOCTL_GBL_IDLE - * OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE) - * OMAP_DSP_IOCTL_POLL + * DSPCTL_IOCTL_GBL_IDLE + * DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE) + * DSPCTL_IOCTL_POLL */ /* @@ -878,16 +961,23 @@ static ssize_t ifver_show(struct device *dev, struct device_attribute *attr, return len; } -static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver); +/* 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())); + return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]); } -static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat); - +/* icrmask */ static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -897,38 +987,43 @@ static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr, static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned short mask; + u16 mask; int ret; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - mask = simple_strtol(buf, NULL, 16); dsp_cpustat_set_icrmask(mask); - if (dsp_is_ready()) { - ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask); + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) { + ret = dsp_setvar(VARID_ICRMASK, mask); if (ret < 0) return ret; } - return strlen(buf); + return count; } -static struct device_attribute dev_attr_icrmask = - __ATTR(icrmask, S_IWUSR | S_IRUGO, icrmask_show, icrmask_store); - +/* loadinfo */ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr, char *buf) { int len; int ret; - static unsigned short val[5]; + u16 val[5]; - if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_LOADINFO, val, 5)) < 0) + if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0) return ret; - /* load info value range is 0(free) - 10000(busy) */ + /* + * 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" @@ -937,72 +1032,15 @@ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr, 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; } -/* - * This is declared at the top of this file. - * - * static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo); - */ - -void mbx1_fbctl_disable(void) -{ - if (!waitqueue_active(&ioctl_wait_q) || - (ioctl_wait_cmd != MBCMD(KFUNC))) { - printk(KERN_WARNING - "mbx: KFUNC:FBCTL command received, " - "but nobody is waiting for it...\n"); - return; - } - ioctl_wait_cmd = 0; - wake_up_interruptible(&ioctl_wait_q); -} - -#ifdef CONFIG_PROC_FS -/* for backward compatibility */ -static int version_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - /* - * This entry is read by 3.1 tools only, so leave it as is. - * 3.2 and later will read from sysfs file. - */ - return sprintf(page, "3.1\n"); -} - -static void __init dsp_ctl_create_proc(void) -{ - struct proc_dir_entry *ent; - - /* version */ - ent = create_proc_read_entry("version", 0, procdir_dsp, - version_read_proc, NULL); - if (ent == NULL) { - printk(KERN_ERR - "omapdsp: failed to register proc device: version\n"); - } -} - -static void dsp_ctl_remove_proc(void) -{ - remove_proc_entry("version", procdir_dsp); -} -#endif /* CONFIG_PROC_FS */ - -struct file_operations dsp_ctl_fops = { - .owner = THIS_MODULE, - .ioctl = dsp_ctl_ioctl, -}; - void __init dsp_ctl_init(void) { device_create_file(&dsp_device.dev, &dev_attr_ifver); device_create_file(&dsp_device.dev, &dev_attr_cpustat); device_create_file(&dsp_device.dev, &dev_attr_icrmask); -#ifdef CONFIG_PROC_FS - dsp_ctl_create_proc(); -#endif } void dsp_ctl_exit(void) @@ -1010,7 +1048,4 @@ void dsp_ctl_exit(void) device_remove_file(&dsp_device.dev, &dev_attr_ifver); device_remove_file(&dsp_device.dev, &dev_attr_cpustat); device_remove_file(&dsp_device.dev, &dev_attr_icrmask); -#ifdef CONFIG_PROC_FS - dsp_ctl_remove_proc(); -#endif } diff --git a/arch/arm/plat-omap/dsp/dsp_ctl_core.c b/arch/arm/plat-omap/dsp/dsp_ctl_core.c index 8207441096b..1d0168d5165 100644 --- a/arch/arm/plat-omap/dsp/dsp_ctl_core.c +++ b/arch/arm/plat-omap/dsp/dsp_ctl_core.c @@ -1,36 +1,31 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_ctl_core.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP control devices core driver + * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2004,2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/07/26: DSP Gateway version 3.3 */ -#include #include #include #include #include -#include -#include "hardware_dsp.h" +#include "dsp.h" #define CTL_MINOR 0 #define MEM_MINOR 1 @@ -86,7 +81,6 @@ int __init dsp_ctl_core_init(void) { int retval; int i; - struct class_device *cdev; retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl", &dsp_ctl_core_fops); @@ -99,7 +93,7 @@ int __init dsp_ctl_core_init(void) dsp_ctl_class = class_create(THIS_MODULE, "dspctl"); for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - cdev = class_device_create(dsp_ctl_class, NULL, + class_device_create(dsp_ctl_class, NULL, MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor), NULL, dev_list[i].devname); diff --git a/arch/arm/plat-omap/dsp/dsp_mbcmd.h b/arch/arm/plat-omap/dsp/dsp_mbcmd.h new file mode 100644 index 00000000000..50cf7789c66 --- /dev/null +++ b/arch/arm/plat-omap/dsp/dsp_mbcmd.h @@ -0,0 +1,107 @@ +/* + * 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 + * + * 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 + * + */ + +/* + * 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_AUDIO_PWR 0x01 + +#define FBCTL_UPD 0x0000 +#define FBCTL_ENABLE 0x0002 +#define FBCTL_DISABLE 0x0003 + +#define AUDIO_PWR_UP 0x0000 +#define AUDIO_PWR_DOWN1 0x0001 +#define AUDIO_PWR_DOWN2 0x0002 + +#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 diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c index 6d2c8110a67..49f633c538a 100644 --- a/arch/arm/plat-omap/dsp/dsp_mem.c +++ b/arch/arm/plat-omap/dsp/dsp_mem.c @@ -1,38 +1,32 @@ /* - * linux/arch/arm/mach-omap/dsp/dsp_mem.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP memory driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation - * - * Written by Toshihiro Kobayashi + * Contact: Toshihiro Kobayashi * * Conversion to mempool API and ARM MMU section mapping * by Paul Mundt * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * Toshihiro Kobayashi - * 2005/06/09: DSP Gateway version 3.3 */ #include #include -#include #include -#include #include #include #include @@ -41,47 +35,110 @@ #include #include #include -#include #include #include #include #include #include -#include +#include #include #include "uaccess_dsp.h" -#include "ipbuf.h" +#include "dsp_mbcmd.h" +#include "../mailbox_hw.h" #include "dsp.h" +#include "ioctl.h" + +#ifdef CONFIG_ARCH_OMAP2 +#define IOMAP_VAL 0x3f +#endif -#define SZ_1MB 0x100000 -#define SZ_64KB 0x10000 -#define SZ_4KB 0x1000 #define SZ_1KB 0x400 +#define SZ_4KB 0x1000 +#define SZ_64KB 0x10000 +#define SZ_1MB 0x100000 +#define SZ_16MB 0x1000000 #define is_aligned(adr,align) (!((adr)&((align)-1))) -#define ORDER_1MB (20 - PAGE_SHIFT) -#define ORDER_64KB (16 - PAGE_SHIFT) #define ORDER_4KB (12 - PAGE_SHIFT) +#define ORDER_64KB (16 - PAGE_SHIFT) +#define ORDER_1MB (20 - PAGE_SHIFT) + +/* + * absorb DSP MMU register size and location difference + */ +#if defined(CONFIG_ARCH_OMAP1) +typedef u16 dsp_mmu_reg_t; +#define dsp_mmu_read_reg(a) omap_readw(a) +#define dsp_mmu_write_reg(v,a) omap_writew(v,a) +#elif defined(CONFIG_ARCH_OMAP2) +typedef u32 dsp_mmu_reg_t; +#define dsp_mmu_read_reg(a) readl(a) +#define dsp_mmu_write_reg(v,a) writel(v,a) +#define dsp_ipi_read_reg(a) readl(a) +#define dsp_ipi_write_reg(v,a) writel(v,a) +#endif -#define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&(PGDIR_MASK)) +#if defined(CONFIG_ARCH_OMAP1) #define dsp_mmu_enable() \ do { \ - omap_writew(DSPMMU_CNTL_MMU_EN | DSPMMU_CNTL_RESET_SW, \ - DSPMMU_CNTL); \ + dsp_mmu_write_reg(DSP_MMU_CNTL_MMU_EN | DSP_MMU_CNTL_RESET_SW, \ + DSP_MMU_CNTL); \ } while(0) #define dsp_mmu_disable() \ - do { omap_writew(0, DSPMMU_CNTL); } while(0) + do { \ + dsp_mmu_write_reg(0, DSP_MMU_CNTL); \ + } while(0) +#define __dsp_mmu_itack() \ + do { \ + dsp_mmu_write_reg(DSP_MMU_IT_ACK_IT_ACK, DSP_MMU_IT_ACK); \ + } while(0) + +#elif defined(CONFIG_ARCH_OMAP2) + +#define dsp_mmu_enable() \ + do { \ + dsp_mmu_write_reg(DSP_MMU_CNTL_MMUENABLE, DSP_MMU_CNTL); \ + } while(0) +#define dsp_mmu_disable() \ + do { \ + dsp_mmu_write_reg(0, DSP_MMU_CNTL); \ + } while(0) +#define dsp_mmu_reset() \ + do { \ + dsp_mmu_write_reg(dsp_mmu_read_reg(DSP_MMU_SYSCONFIG) | \ + DSP_MMU_SYSCONFIG_SOFTRESET, \ + DSP_MMU_SYSCONFIG); \ + } while(0) + +#endif /* CONFIG_ARCH_OMAP2 */ + #define dsp_mmu_flush() \ do { \ - omap_writew(DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY, \ - DSPMMU_FLUSH_ENTRY); \ + dsp_mmu_write_reg(DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY, \ + DSP_MMU_FLUSH_ENTRY); \ } while(0) #define __dsp_mmu_gflush() \ - do { omap_writew(DSPMMU_GFLUSH_GFLUSH, DSPMMU_GFLUSH); } while(0) -#define __dsp_mmu_itack() \ - do { omap_writew(DSPMMU_IT_ACK_IT_ACK, DSPMMU_IT_ACK); } while(0) + do { \ + dsp_mmu_write_reg(DSP_MMU_GFLUSH_GFLUSH, DSP_MMU_GFLUSH); \ + } while(0) +/* + * absorb register name difference + */ +#ifdef CONFIG_ARCH_OMAP1 +#define DSP_MMU_CAM_P DSP_MMU_CAM_L_P +#define DSP_MMU_CAM_V DSP_MMU_CAM_L_V +#define DSP_MMU_CAM_PAGESIZE_MASK DSP_MMU_CAM_L_PAGESIZE_MASK +#define DSP_MMU_CAM_PAGESIZE_1MB DSP_MMU_CAM_L_PAGESIZE_1MB +#define DSP_MMU_CAM_PAGESIZE_64KB DSP_MMU_CAM_L_PAGESIZE_64KB +#define DSP_MMU_CAM_PAGESIZE_4KB DSP_MMU_CAM_L_PAGESIZE_4KB +#define DSP_MMU_CAM_PAGESIZE_1KB DSP_MMU_CAM_L_PAGESIZE_1KB +#endif /* CONFIG_ARCH_OMAP1 */ + +/* + * 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 @@ -93,29 +150,62 @@ #define set_emiff_dma_prio(prio) \ do { \ omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \ - ~EMIF_PRIO_DMA_MASK) | \ + ~EMIF_PRIO_DMA_MASK) | \ ((prio) << EMIF_PRIO_DMA_SHIFT), \ OMAP_TC_OCPT1_PRIOR); \ } while(0) +#endif /* CONFIG_ARCH_OMAP1 */ -enum exmap_type { +enum exmap_type_e { EXMAP_TYPE_MEM, EXMAP_TYPE_FB }; -struct exmap_tbl { +struct exmap_tbl_entry { unsigned int valid:1; - unsigned int cntnu:1; /* grouping */ + unsigned int prsvd:1; /* preserved */ int usecount; /* reference count by mmap */ - enum exmap_type type; + enum exmap_type_e type; void *buf; /* virtual address of the buffer, * i.e. 0xc0000000 - */ void *vadr; /* DSP shadow space, * i.e. 0xe0000000 - 0xe0ffffff */ unsigned int order; + struct { + int prev; + int next; + } link; /* grouping */ }; -#define DSPMMU_TLB_LINES 32 -static struct exmap_tbl exmap_tbl[DSPMMU_TLB_LINES]; + +#define INIT_EXMAP_TBL_ENTRY(ent,b,v,typ,od) \ + do {\ + (ent)->buf = (b); \ + (ent)->vadr = (v); \ + (ent)->valid = 1; \ + (ent)->prsvd = 0; \ + (ent)->usecount = 0; \ + (ent)->type = (typ); \ + (ent)->order = (od); \ + (ent)->link.next = -1; \ + (ent)->link.prev = -1; \ + } while (0) + +#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent,b,v) \ + do {\ + (ent)->buf = (b); \ + (ent)->vadr = (v); \ + (ent)->valid = 1; \ + (ent)->prsvd = 1; \ + (ent)->usecount = 0; \ + (ent)->type = EXMAP_TYPE_MEM; \ + (ent)->order = 0; \ + (ent)->link.next = -1; \ + (ent)->link.prev = -1; \ + } while (0) + +#define DSP_MMU_TLB_LINES 32 +static struct exmap_tbl_entry exmap_tbl[DSP_MMU_TLB_LINES]; +static int exmap_preserved_cnt; static DECLARE_RWSEM(exmap_sem); #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL @@ -123,23 +213,123 @@ static struct omapfb_notifier_block *omapfb_nb; static int omapfb_ready; #endif -static int dsp_exunmap(unsigned long dspadr); +struct cam_ram_regset { +#if defined(CONFIG_ARCH_OMAP1) + dsp_mmu_reg_t cam_h; + dsp_mmu_reg_t cam_l; + dsp_mmu_reg_t ram_h; + dsp_mmu_reg_t ram_l; +#elif defined(CONFIG_ARCH_OMAP2) + dsp_mmu_reg_t cam; + dsp_mmu_reg_t ram; +#endif +}; + +struct tlb_entry { + dsp_long_t va; + unsigned long pa; + dsp_mmu_reg_t pgsz, prsvd, valid; +#if defined(CONFIG_ARCH_OMAP1) + dsp_mmu_reg_t ap; +#elif defined(CONFIG_ARCH_OMAP2) + dsp_mmu_reg_t endian, elsz, mixed; +#endif +}; + +#if defined(CONFIG_ARCH_OMAP1) +#define INIT_TLB_ENTRY(ent,v,p,ps) \ + do { \ + (ent)->va = (v); \ + (ent)->pa = (p); \ + (ent)->pgsz = (ps); \ + (ent)->prsvd = 0; \ + (ent)->ap = DSP_MMU_RAM_L_AP_FA; \ + } while (0) +#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \ + do { \ + (ent)->va = (v); \ + (ent)->pa = (p); \ + (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ + (ent)->prsvd = DSP_MMU_CAM_P; \ + (ent)->ap = DSP_MMU_RAM_L_AP_FA; \ + } while (0) +#elif defined(CONFIG_ARCH_OMAP2) +#define INIT_TLB_ENTRY(ent,v,p,ps) \ + do { \ + (ent)->va = (v); \ + (ent)->pa = (p); \ + (ent)->pgsz = (ps); \ + (ent)->prsvd = 0; \ + (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ + (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \ + (ent)->mixed = 0; \ + } while (0) +#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \ + do { \ + (ent)->va = (v); \ + (ent)->pa = (p); \ + (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ + (ent)->prsvd = DSP_MMU_CAM_P; \ + (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ + (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \ + (ent)->mixed = 0; \ + } while (0) +#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent,v,p) \ + do { \ + (ent)->va = (v); \ + (ent)->pa = (p); \ + (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ + (ent)->prsvd = DSP_MMU_CAM_P; \ + (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ + (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_32; \ + (ent)->mixed = 0; \ + } while (0) +#endif + +#if defined(CONFIG_ARCH_OMAP1) +#define cam_ram_valid(cr) ((cr).cam_l & DSP_MMU_CAM_V) +#elif defined(CONFIG_ARCH_OMAP2) +#define cam_ram_valid(cr) ((cr).cam & DSP_MMU_CAM_V) +#endif + +struct tlb_lock { + int base; + int victim; +}; + +static int dsp_exunmap(dsp_long_t dspadr); static void *dspvect_page; -static unsigned long dsp_fault_adr; +static u32 dsp_fault_adr; static struct mem_sync_struct mem_sync; -static void *mempool_alloc_from_pool(mempool_t *pool, - unsigned int __nocast gfp_mask) +static ssize_t mmu_show(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t mempool_show(struct device *dev, struct device_attribute *attr, + char *buf); + +static struct device_attribute dev_attr_mmu = __ATTR_RO(mmu); +static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap); +static struct device_attribute dev_attr_mempool = __ATTR_RO(mempool); + +/* + * special mempool function: + * hope this goes to mm/mempool.c + */ +static void *mempool_alloc_from_pool(mempool_t *pool, gfp_t gfp_mask) { - spin_lock_irq(&pool->lock); + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); if (likely(pool->curr_nr)) { void *element = pool->elements[--pool->curr_nr]; - spin_unlock_irq(&pool->lock); + spin_unlock_irqrestore(&pool->lock, flags); return element; } + spin_unlock_irqrestore(&pool->lock, flags); - spin_unlock_irq(&pool->lock); return mempool_alloc(pool, gfp_mask); } @@ -233,6 +423,7 @@ static int dsp_kmem_reserve(unsigned long size) "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size); return -EINVAL; } + if (size > DSPSPACE_SIZE) { printk(KERN_ERR "omapdsp: size(0x%lx) is larger than DSP memory space " @@ -286,14 +477,12 @@ static void dsp_mem_free_pages(unsigned long buf, unsigned int order) for (page = ps; page < pe; page++) ClearPageReserved(page); - if (buf) { - if ((order == ORDER_64KB) && likely(kmem_pool_64K)) - mempool_free((void *)buf, kmem_pool_64K); - else if ((order == ORDER_1MB) && likely(kmem_pool_1M)) - mempool_free((void *)buf, kmem_pool_1M); - else - free_pages(buf, order); - } + if ((order == ORDER_64KB) && likely(kmem_pool_64K)) + mempool_free((void *)buf, kmem_pool_64K); + else if ((order == ORDER_1MB) && likely(kmem_pool_1M)) + mempool_free((void *)buf, kmem_pool_1M); + else + free_pages(buf, order); } static inline void @@ -321,6 +510,7 @@ exmap_alloc_pte(unsigned long virt, unsigned long phys, pgprot_t prot) set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); } +#if 0 static inline int exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot) { @@ -344,6 +534,7 @@ exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot) return 0; } +#endif /* * ARM MMU operations @@ -400,6 +591,11 @@ static int exmap_set_armmmu(unsigned long virt, unsigned long phys, return 0; } + /* XXX: T.Kobayashi + * A process can have old mappings. if we want to clear a pmd, + * we need to do it for all proceeses that use the old mapping. + */ +#if 0 static inline void exmap_clear_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end) { @@ -457,14 +653,16 @@ exmap_clear_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end) exmap_clear_pmd_range(pud, addr, next); } while (pud++, addr = next, addr != end); } +#endif static void exmap_clear_armmmu(unsigned long virt, unsigned long size) { +#if 0 unsigned long next, end; pgd_t *pgd; printk(KERN_DEBUG - "omapdsp: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n", + "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n", virt, size); pgd = pgd_offset_k(virt); @@ -476,6 +674,29 @@ static void exmap_clear_armmmu(unsigned long virt, unsigned long size) exmap_clear_pud_range(pgd, virt, next); } while (pgd++, virt = next, virt != end); +#else + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + printk(KERN_DEBUG + "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n", + virt, size); + + while (size >= PAGE_SIZE) { + pgd = pgd_offset_k(virt); + pud = pud_offset(pgd, virt); + pmd = pmd_offset(pud, virt); + pte = pte_offset_kernel(pmd, virt); + + pte_clear(&init_mm, virt, pte); + size -= PAGE_SIZE; + virt += PAGE_SIZE; + } + + BUG_ON(size); +#endif } static int exmap_valid(void *vadr, size_t len) @@ -484,10 +705,10 @@ static int exmap_valid(void *vadr, size_t len) int i; start: - for (i = 0; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { void *mapadr; unsigned long mapsize; - struct exmap_tbl *ent = &exmap_tbl[i]; + struct exmap_tbl_entry *ent = &exmap_tbl[i]; if (!ent->valid) continue; @@ -576,18 +797,17 @@ void exmap_use(void *vadr, size_t len) int i; down_write(&exmap_sem); - for (i = 0; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { void *mapadr; unsigned long mapsize; - struct exmap_tbl *ent = &exmap_tbl[i]; + struct exmap_tbl_entry *ent = &exmap_tbl[i]; if (!ent->valid) continue; mapadr = (void *)ent->vadr; mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) { + if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) ent->usecount++; - } } up_write(&exmap_sem); } @@ -597,18 +817,17 @@ void exmap_unuse(void *vadr, size_t len) int i; down_write(&exmap_sem); - for (i = 0; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { void *mapadr; unsigned long mapsize; - struct exmap_tbl *ent = &exmap_tbl[i]; + struct exmap_tbl_entry *ent = &exmap_tbl[i]; if (!ent->valid) continue; mapadr = (void *)ent->vadr; mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) { + if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) ent->usecount--; - } } up_write(&exmap_sem); } @@ -628,10 +847,10 @@ unsigned long dsp_virt_to_phys(void *vadr, size_t *len) } /* EXRAM */ - for (i = 0; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { void *mapadr; unsigned long mapsize; - struct exmap_tbl *ent = &exmap_tbl[i]; + struct exmap_tbl_entry *ent = &exmap_tbl[i]; if (!ent->valid) continue; @@ -650,151 +869,188 @@ unsigned long dsp_virt_to_phys(void *vadr, size_t *len) /* * DSP MMU operations */ -static __inline__ unsigned short get_cam_l_va_mask(unsigned short slst) -{ - switch (slst) { - case DSPMMU_CAM_L_SLST_1MB: - return DSPMMU_CAM_L_VA_TAG_L1_MASK | - DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB; - case DSPMMU_CAM_L_SLST_64KB: - return DSPMMU_CAM_L_VA_TAG_L1_MASK | - DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB; - case DSPMMU_CAM_L_SLST_4KB: - return DSPMMU_CAM_L_VA_TAG_L1_MASK | - DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB; - case DSPMMU_CAM_L_SLST_1KB: - return DSPMMU_CAM_L_VA_TAG_L1_MASK | - DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB; +#ifdef CONFIG_ARCH_OMAP1 +static dsp_mmu_reg_t get_cam_l_va_mask(dsp_mmu_reg_t pgsz) +{ + switch (pgsz) { + case DSP_MMU_CAM_PAGESIZE_1MB: + return DSP_MMU_CAM_L_VA_TAG_L1_MASK | + DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB; + case DSP_MMU_CAM_PAGESIZE_64KB: + return DSP_MMU_CAM_L_VA_TAG_L1_MASK | + DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB; + case DSP_MMU_CAM_PAGESIZE_4KB: + return DSP_MMU_CAM_L_VA_TAG_L1_MASK | + DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB; + case DSP_MMU_CAM_PAGESIZE_1KB: + return DSP_MMU_CAM_L_VA_TAG_L1_MASK | + DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB; } return 0; } +#endif /* CONFIG_ARCH_OMAP1 */ + +#if defined(CONFIG_ARCH_OMAP1) +#define get_cam_va_mask(pgsz) \ + ((u32)DSP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \ + (u32)get_cam_l_va_mask(pgsz) << 6) +#elif defined(CONFIG_ARCH_OMAP2) +#define get_cam_va_mask(pgsz) \ + ((pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \ + (pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? 0xfff00000 : \ + (pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \ + (pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? 0xfffff000 : 0) +#endif /* CONFIG_ARCH_OMAP2 */ -static __inline__ void get_tlb_lock(int *base, int *victim) +static void get_tlb_lock(struct tlb_lock *tlb_lock) { - unsigned short lock = omap_readw(DSPMMU_LOCK); - if (base != NULL) - *base = (lock & DSPMMU_LOCK_BASE_MASK) - >> DSPMMU_LOCK_BASE_SHIFT; - if (victim != NULL) - *victim = (lock & DSPMMU_LOCK_VICTIM_MASK) - >> DSPMMU_LOCK_VICTIM_SHIFT; + dsp_mmu_reg_t lock = dsp_mmu_read_reg(DSP_MMU_LOCK); + + tlb_lock->base = (lock & DSP_MMU_LOCK_BASE_MASK) >> + DSP_MMU_LOCK_BASE_SHIFT; + tlb_lock->victim = (lock & DSP_MMU_LOCK_VICTIM_MASK) >> + DSP_MMU_LOCK_VICTIM_SHIFT; } -static __inline__ void set_tlb_lock(int base, int victim) +static void set_tlb_lock(struct tlb_lock *tlb_lock) { - omap_writew((base << DSPMMU_LOCK_BASE_SHIFT) | - (victim << DSPMMU_LOCK_VICTIM_SHIFT), DSPMMU_LOCK); + dsp_mmu_write_reg((tlb_lock->base << DSP_MMU_LOCK_BASE_SHIFT) | + (tlb_lock->victim << DSP_MMU_LOCK_VICTIM_SHIFT), + DSP_MMU_LOCK); } -static __inline__ void __read_tlb(unsigned short lbase, unsigned short victim, - unsigned short *cam_h, unsigned short *cam_l, - unsigned short *ram_h, unsigned short *ram_l) +static void __read_tlb(struct tlb_lock *tlb_lock, struct cam_ram_regset *cr) { /* set victim */ - set_tlb_lock(lbase, victim); + set_tlb_lock(tlb_lock); +#if defined(CONFIG_ARCH_OMAP1) /* read a TLB entry */ - omap_writew(DSPMMU_LD_TLB_RD, DSPMMU_LD_TLB); - - if (cam_h != NULL) - *cam_h = omap_readw(DSPMMU_READ_CAM_H); - if (cam_l != NULL) - *cam_l = omap_readw(DSPMMU_READ_CAM_L); - if (ram_h != NULL) - *ram_h = omap_readw(DSPMMU_READ_RAM_H); - if (ram_l != NULL) - *ram_l = omap_readw(DSPMMU_READ_RAM_L); + dsp_mmu_write_reg(DSP_MMU_LD_TLB_RD, DSP_MMU_LD_TLB); + + cr->cam_h = dsp_mmu_read_reg(DSP_MMU_READ_CAM_H); + cr->cam_l = dsp_mmu_read_reg(DSP_MMU_READ_CAM_L); + cr->ram_h = dsp_mmu_read_reg(DSP_MMU_READ_RAM_H); + cr->ram_l = dsp_mmu_read_reg(DSP_MMU_READ_RAM_L); +#elif defined(CONFIG_ARCH_OMAP2) + cr->cam = dsp_mmu_read_reg(DSP_MMU_READ_CAM); + cr->ram = dsp_mmu_read_reg(DSP_MMU_READ_RAM); +#endif } -static __inline__ void __load_tlb(unsigned short cam_h, unsigned short cam_l, - unsigned short ram_h, unsigned short ram_l) +static void __load_tlb(struct cam_ram_regset *cr) { - omap_writew(cam_h, DSPMMU_CAM_H); - omap_writew(cam_l, DSPMMU_CAM_L); - omap_writew(ram_h, DSPMMU_RAM_H); - omap_writew(ram_l, DSPMMU_RAM_L); +#if defined(CONFIG_ARCH_OMAP1) + dsp_mmu_write_reg(cr->cam_h, DSP_MMU_CAM_H); + dsp_mmu_write_reg(cr->cam_l, DSP_MMU_CAM_L); + dsp_mmu_write_reg(cr->ram_h, DSP_MMU_RAM_H); + dsp_mmu_write_reg(cr->ram_l, DSP_MMU_RAM_L); +#elif defined(CONFIG_ARCH_OMAP2) + dsp_mmu_write_reg(cr->cam | DSP_MMU_CAM_V, DSP_MMU_CAM); + dsp_mmu_write_reg(cr->ram, DSP_MMU_RAM); +#endif /* flush the entry */ dsp_mmu_flush(); /* load a TLB entry */ - omap_writew(DSPMMU_LD_TLB_LD, DSPMMU_LD_TLB); + dsp_mmu_write_reg(DSP_MMU_LD_TLB_LD, DSP_MMU_LD_TLB); } -static int dsp_mmu_load_tlb(unsigned long vadr, unsigned long padr, - unsigned short slst, unsigned short prsvd, - unsigned short ap) +static int dsp_mmu_load_tlb(struct tlb_entry *tlb_ent) { - int lbase, victim; - unsigned short cam_l_va_mask; + struct tlb_lock tlb_lock; + struct cam_ram_regset cr; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(dsp_ck_handle); + omap_dsp_request_mem(); +#endif - get_tlb_lock(&lbase, NULL); - for (victim = 0; victim < lbase; victim++) { - unsigned short cam_l; + get_tlb_lock(&tlb_lock); + for (tlb_lock.victim = 0; + tlb_lock.victim < tlb_lock.base; + tlb_lock.victim++) { + struct cam_ram_regset tmp_cr; /* read a TLB entry */ - __read_tlb(lbase, victim, NULL, &cam_l, NULL, NULL); - if (!(cam_l & DSPMMU_CAM_L_V)) + __read_tlb(&tlb_lock, &tmp_cr); + if (!cam_ram_valid(tmp_cr)) goto found_victim; } - set_tlb_lock(lbase, victim); + set_tlb_lock(&tlb_lock); found_victim: /* The last (31st) entry cannot be locked? */ - if (victim == 31) { + if (tlb_lock.victim == 31) { printk(KERN_ERR "omapdsp: TLB is full.\n"); return -EBUSY; } - cam_l_va_mask = get_cam_l_va_mask(slst); - if (vadr & - ~(DSPMMU_CAM_H_VA_TAG_H_MASK << 22 | - (unsigned long)cam_l_va_mask << 6)) { + if (tlb_ent->va & ~get_cam_va_mask(tlb_ent->pgsz)) { printk(KERN_ERR - "omapdsp: mapping vadr (0x%06lx) is not " - "aligned boundary\n", vadr); + "omapdsp: mapping vadr (0x%06x) is not " + "aligned boundary\n", tlb_ent->va); return -EINVAL; } - __load_tlb(vadr >> 22, (vadr >> 6 & cam_l_va_mask) | prsvd | slst, - padr >> 16, (padr & DSPMMU_RAM_L_RAM_LSB_MASK) | ap); +#if defined(CONFIG_ARCH_OMAP1) + cr.cam_h = tlb_ent->va >> 22; + cr.cam_l = (tlb_ent->va >> 6 & get_cam_l_va_mask(tlb_ent->pgsz)) | + tlb_ent->prsvd | tlb_ent->pgsz; + cr.ram_h = tlb_ent->pa >> 16; + cr.ram_l = (tlb_ent->pa & DSP_MMU_RAM_L_RAM_LSB_MASK) | tlb_ent->ap; +#elif defined(CONFIG_ARCH_OMAP2) + cr.cam = (tlb_ent->va & DSP_MMU_CAM_VATAG_MASK) | + tlb_ent->prsvd | tlb_ent->pgsz; + cr.ram = tlb_ent->pa | tlb_ent->endian | tlb_ent->elsz; +#endif + __load_tlb(&cr); /* update lock base */ - if (victim == lbase) - lbase++; - set_tlb_lock(lbase, lbase); + if (tlb_lock.victim == tlb_lock.base) + tlb_lock.base++; + tlb_lock.victim = tlb_lock.base; + set_tlb_lock(&tlb_lock); +#ifdef CONFIG_ARCH_OMAP1 + omap_dsp_release_mem(); clk_disable(dsp_ck_handle); +#endif return 0; } -static int dsp_mmu_clear_tlb(unsigned long vadr) +static int dsp_mmu_clear_tlb(dsp_long_t vadr) { - int lbase; + struct tlb_lock tlb_lock; int i; int max_valid = 0; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(dsp_ck_handle); + omap_dsp_request_mem(); +#endif - get_tlb_lock(&lbase, NULL); - for (i = 0; i < lbase; i++) { - unsigned short cam_h, cam_l; - unsigned short cam_l_va_mask, cam_vld, slst; - unsigned long cam_va; + get_tlb_lock(&tlb_lock); + for (i = 0; i < tlb_lock.base; i++) { + struct cam_ram_regset cr; + dsp_long_t cam_va; + dsp_mmu_reg_t pgsz; /* read a TLB entry */ - __read_tlb(lbase, i, &cam_h, &cam_l, NULL, NULL); - - cam_vld = cam_l & DSPMMU_CAM_L_V; - if (!cam_vld) + tlb_lock.victim = i; + __read_tlb(&tlb_lock, &cr); + if (!cam_ram_valid(cr)) continue; - slst = cam_l & DSPMMU_CAM_L_SLST_MASK; - cam_l_va_mask = get_cam_l_va_mask(slst); - cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 | - (unsigned long)(cam_l & cam_l_va_mask) << 6; +#if defined(CONFIG_ARCH_OMAP1) + pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK; + cam_va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 | + (u32)(cr.cam_l & get_cam_l_va_mask(pgsz)) << 6; +#elif defined(CONFIG_ARCH_OMAP2) + pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK; + cam_va = cr.cam & get_cam_va_mask(pgsz); +#endif if (cam_va == vadr) /* flush the entry */ @@ -804,46 +1060,63 @@ static int dsp_mmu_clear_tlb(unsigned long vadr) } /* set new lock base */ - set_tlb_lock(max_valid+1, max_valid+1); + tlb_lock.base = max_valid + 1; + tlb_lock.victim = max_valid + 1; + set_tlb_lock(&tlb_lock); +#ifdef CONFIG_ARCH_OMAP1 + omap_dsp_release_mem(); clk_disable(dsp_ck_handle); +#endif return 0; } static void dsp_mmu_gflush(void) { + struct tlb_lock tlb_lock; + +#ifdef CONFIG_ARCH_OMAP1 clk_enable(dsp_ck_handle); + omap_dsp_request_mem(); +#endif __dsp_mmu_gflush(); - set_tlb_lock(1, 1); + tlb_lock.base = exmap_preserved_cnt; + tlb_lock.victim = exmap_preserved_cnt; + set_tlb_lock(&tlb_lock); +#ifdef CONFIG_ARCH_OMAP1 + omap_dsp_release_mem(); clk_disable(dsp_ck_handle); +#endif } /* * dsp_exmap() * - * OMAP_DSP_MEM_IOCTL_EXMAP ioctl calls this function with padr=0. + * MEM_IOCTL_EXMAP ioctl calls this function with padr=0. * In this case, the buffer for DSP is allocated in this routine, * then it is mapped. * On the other hand, for example - frame buffer sharing, calls * this function with padr set. It means some known address space * pointed with padr is going to be shared with DSP. */ -static int dsp_exmap(unsigned long dspadr, unsigned long padr, - unsigned long size, enum exmap_type type) +static int dsp_exmap(dsp_long_t dspadr, unsigned long padr, unsigned long size, + enum exmap_type_e type) { - unsigned short slst; + dsp_mmu_reg_t pgsz; void *buf; unsigned int order = 0; unsigned long unit; - unsigned int cntnu = 0; - unsigned long _dspadr = dspadr; + int prev = -1; + dsp_long_t _dspadr = dspadr; unsigned long _padr = padr; void *_vadr = dspbyte_to_virt(dspadr); unsigned long _size = size; - struct exmap_tbl *exmap_ent; + struct tlb_entry tlb_ent; + struct exmap_tbl_entry *exmap_ent; int status; + int idx; int i; #define MINIMUM_PAGESZ SZ_4KB @@ -857,7 +1130,7 @@ static int dsp_exmap(unsigned long dspadr, unsigned long padr, } if (!is_aligned(dspadr, MINIMUM_PAGESZ)) { printk(KERN_ERR - "omapdsp: DSP address(0x%lx) is not aligned.\n", dspadr); + "omapdsp: DSP address(0x%x) is not aligned.\n", dspadr); return -EINVAL; } if (!is_aligned(padr, MINIMUM_PAGESZ)) { @@ -880,9 +1153,9 @@ static int dsp_exmap(unsigned long dspadr, unsigned long padr, down_write(&exmap_sem); /* overlap check */ - for (i = 0; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { unsigned long mapsize; - struct exmap_tbl *tmp_ent = &exmap_tbl[i]; + struct exmap_tbl_entry *tmp_ent = &exmap_tbl[i]; if (!tmp_ent->valid) continue; @@ -898,8 +1171,8 @@ static int dsp_exmap(unsigned long dspadr, unsigned long padr, start: buf = NULL; /* Are there any free TLB lines? */ - for (i = 0; i < DSPMMU_TLB_LINES; i++) { - if (!exmap_tbl[i].valid) + for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) { + if (!exmap_tbl[idx].valid) goto found_free; } printk(KERN_ERR "omapdsp: DSP TLB is full.\n"); @@ -907,21 +1180,26 @@ start: goto fail; found_free: - exmap_ent = &exmap_tbl[i]; + exmap_ent = &exmap_tbl[idx]; + /* + * we don't use + * 1KB mapping in OMAP1, + * 16MB mapping in OMAP2. + */ if ((_size >= SZ_1MB) && (is_aligned(_padr, SZ_1MB) || (padr == 0)) && is_aligned(_dspadr, SZ_1MB)) { unit = SZ_1MB; - slst = DSPMMU_CAM_L_SLST_1MB; + pgsz = DSP_MMU_CAM_PAGESIZE_1MB; } else if ((_size >= SZ_64KB) && (is_aligned(_padr, SZ_64KB) || (padr == 0)) && is_aligned(_dspadr, SZ_64KB)) { unit = SZ_64KB; - slst = DSPMMU_CAM_L_SLST_64KB; + pgsz = DSP_MMU_CAM_PAGESIZE_64KB; } else { unit = SZ_4KB; - slst = DSPMMU_CAM_L_SLST_4KB; + pgsz = DSP_MMU_CAM_PAGESIZE_4KB; } order = get_order(unit); @@ -962,19 +1240,17 @@ found_free: goto fail; /* loading DSP TLB entry */ - status = dsp_mmu_load_tlb(_dspadr, _padr, slst, 0, DSPMMU_RAM_L_AP_FA); + INIT_TLB_ENTRY(&tlb_ent, _dspadr, _padr, pgsz); + status = dsp_mmu_load_tlb(&tlb_ent); if (status < 0) { exmap_clear_armmmu((unsigned long)_vadr, unit); goto fail; } - exmap_ent->buf = buf; - exmap_ent->vadr = _vadr; - exmap_ent->order = order; - exmap_ent->valid = 1; - exmap_ent->cntnu = cntnu; - exmap_ent->type = type; - exmap_ent->usecount = 0; + INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order); + exmap_ent->link.prev = prev; + if (prev >= 0) + exmap_tbl[prev].link.next = idx; if ((_size -= unit) == 0) { /* normal completion */ up_write(&exmap_sem); @@ -984,7 +1260,7 @@ found_free: _dspadr += unit; _vadr += unit; _padr = padr ? _padr + unit : 0; - cntnu = 1; + prev = idx; goto start; fail: @@ -995,7 +1271,7 @@ fail: return status; } -static unsigned long unmap_free_arm(struct exmap_tbl *ent) +static unsigned long unmap_free_arm(struct exmap_tbl_entry *ent) { unsigned long size; @@ -1031,26 +1307,26 @@ static unsigned long unmap_free_arm(struct exmap_tbl *ent) return size; } -static int dsp_exunmap(unsigned long dspadr) +static int dsp_exunmap(dsp_long_t dspadr) { void *vadr; unsigned long size; int total = 0; - struct exmap_tbl *ent; + struct exmap_tbl_entry *ent; int idx; vadr = dspbyte_to_virt(dspadr); down_write(&exmap_sem); - for (idx = 0; idx < DSPMMU_TLB_LINES; idx++) { + for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) { ent = &exmap_tbl[idx]; - if (!ent->valid) + if ((!ent->valid) || ent->prsvd) continue; if (ent->vadr == vadr) goto found_map; } up_write(&exmap_sem); printk(KERN_WARNING - "omapdsp: address %06lx not found in exmap_tbl.\n", dspadr); + "omapdsp: address %06x not found in exmap_tbl.\n", dspadr); return -EINVAL; found_map: @@ -1075,13 +1351,9 @@ found_map: /* flush TLB */ flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size); - /* check if next mapping is in same group */ - if (++idx == DSPMMU_TLB_LINES) + if ((idx = ent->link.next) < 0) goto up_out; /* normal completion */ ent = &exmap_tbl[idx]; - if (!ent->valid || !ent->cntnu) - goto up_out; /* normal completion */ - dspadr += size; vadr += size; if (ent->vadr == vadr) @@ -1101,7 +1373,7 @@ up_out: static void exmap_flush(void) { - struct exmap_tbl *ent; + struct exmap_tbl_entry *ent; int i; down_write(&exmap_sem); @@ -1109,10 +1381,9 @@ static void exmap_flush(void) /* clearing DSP TLB entry */ dsp_mmu_gflush(); - /* exmap_tbl[0] should be preserved */ - for (i = 1; i < DSPMMU_TLB_LINES; i++) { + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { ent = &exmap_tbl[i]; - if (ent->valid) { + if (ent->valid && (!ent->prsvd)) { unmap_free_arm(ent); ent->valid = 0; } @@ -1145,9 +1416,9 @@ static int omapfb_notifier_cb(struct omapfb_notifier_block *omapfb_nb, } #endif -static int dsp_fbexport(unsigned long *dspadr) +static int dsp_fbexport(dsp_long_t *dspadr) { - unsigned long dspadr_actual; + dsp_long_t dspadr_actual; unsigned long padr_sys, padr, fbsz_sys, fbsz; int cnt; #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL @@ -1196,7 +1467,7 @@ static int dsp_fbexport(unsigned long *dspadr) /* (fbsz > SZ_4KB) ? */ *dspadr; if (dspadr_actual != *dspadr) printk(KERN_DEBUG - "omapdsp: actual dspadr for FBEXPORT = %08lx\n", + "omapdsp: actual dspadr for FBEXPORT = %08x\n", dspadr_actual); *dspadr = dspadr_actual; @@ -1218,8 +1489,10 @@ static int dsp_fbexport(unsigned long *dspadr) padr_sys, fbsz_sys, padr, fbsz); } +#ifdef CONFIG_ARCH_OMAP1 /* increase the DMA priority */ set_emiff_dma_prio(15); +#endif #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL omapfb_nb = kmalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL); @@ -1241,7 +1514,7 @@ static int dsp_fbexport(unsigned long *dspadr) #else /* CONFIG_OMAP_DSP_FBEXPORT */ -static int dsp_fbexport(unsigned long *dspadr) +static int dsp_fbexport(dsp_long_t *dspadr) { printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n"); return -EINVAL; @@ -1249,64 +1522,176 @@ static int dsp_fbexport(unsigned long *dspadr) #endif /* CONFIG_OMAP_DSP_FBEXPORT */ +static void exmap_setup_preserved_mem_page(void *buf, dsp_long_t dspadr, + int exmap_idx) +{ + unsigned long phys; + void *virt; + struct tlb_entry tlb_ent; + + phys = __pa(buf); + virt = dspbyte_to_virt(dspadr); + exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); + INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], buf, virt); + INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, dspadr, phys); + dsp_mmu_load_tlb(&tlb_ent); +} + +static void exmap_clear_mem_page(dsp_long_t dspadr) +{ + void *virt; + + virt = dspbyte_to_virt(dspadr); + exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE); + /* DSP MMU is shutting down. not handled here. */ +} + +#ifdef CONFIG_ARCH_OMAP2 +static void exmap_setup_iomap_page(unsigned long phys, unsigned long dsp_io_adr, + int exmap_idx) +{ + dsp_long_t dspadr; + void *virt; + struct tlb_entry tlb_ent; + + dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1); + virt = dspbyte_to_virt(dspadr); + exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); + INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], NULL, virt); + INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys); + dsp_mmu_load_tlb(&tlb_ent); +} + +static void exmap_clear_iomap_page(unsigned long dsp_io_adr) +{ + dsp_long_t dspadr; + void *virt; + + dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1); + virt = dspbyte_to_virt(dspadr); + exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE); + /* DSP MMU is shutting down. not handled here. */ +} +#endif /* CONFIG_ARCH_OMAP2 */ + +#define OMAP2420_GPT5_BASE (L4_24XX_BASE + 0x7c000) +#define OMAP2420_GPT6_BASE (L4_24XX_BASE + 0x7e000) +#define OMAP2420_GPT7_BASE (L4_24XX_BASE + 0x80000) +#define OMAP2420_GPT8_BASE (L4_24XX_BASE + 0x82000) +#define OMAP24XX_EAC_BASE (L4_24XX_BASE + 0x90000) + +static int exmap_setup_preserved_entries(void) +{ + int n = 0; + + exmap_setup_preserved_mem_page(dspvect_page, DSP_INIT_PAGE, n++); +#ifdef CONFIG_ARCH_OMAP2 + exmap_setup_iomap_page(OMAP24XX_PRCM_BASE, 0x7000, n++); +#ifdef CONFIG_ARCH_OMAP2420 + exmap_setup_iomap_page(OMAP2420_GPT5_BASE, 0xe000, n++); + exmap_setup_iomap_page(OMAP2420_GPT6_BASE, 0xe800, n++); + exmap_setup_iomap_page(OMAP2420_GPT7_BASE, 0xf000, n++); + exmap_setup_iomap_page(OMAP2420_GPT8_BASE, 0xf800, n++); +#endif /* CONFIG_ARCH_OMAP2420 */ + exmap_setup_iomap_page(OMAP24XX_EAC_BASE, 0x10000, n++); + exmap_setup_iomap_page(OMAP24XX_MAILBOX_BASE, 0x11000, n++); +#endif /* CONFIG_ARCH_OMAP2 */ + + return n; +} + +static void exmap_clear_preserved_entries(void) +{ + exmap_clear_mem_page(DSP_INIT_PAGE); +#ifdef CONFIG_ARCH_OMAP2 + exmap_clear_iomap_page(0x7000); /* PRCM */ +#ifdef CONFIG_ARCH_OMAP2420 + exmap_clear_iomap_page(0xe000); /* GPT5 */ + exmap_clear_iomap_page(0xe800); /* GPT6 */ + exmap_clear_iomap_page(0xf000); /* GPT7 */ + exmap_clear_iomap_page(0xf800); /* GPT8 */ +#endif /* CONFIG_ARCH_OMAP2420 */ + exmap_clear_iomap_page(0x10000); /* EAC */ + exmap_clear_iomap_page(0x11000); /* MAILBOX */ +#endif /* CONFIG_ARCH_OMAP2 */ +} + +#ifdef CONFIG_ARCH_OMAP1 static int dsp_mmu_itack(void) { unsigned long dspadr; printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n"); - if (!dsp_err_mmu_isset()) { + if (!dsp_err_isset(ERRCODE_MMU)) { printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n"); return -EINVAL; } dspadr = dsp_fault_adr & ~(SZ_4K-1); dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM); /* FIXME: reserve TLB entry for this */ printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n"); - dsp_runlevel(OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY); + dsp_set_runlevel(RUNLEVEL_RECOVERY); __dsp_mmu_itack(); udelay(100); dsp_exunmap(dspadr); - dsp_err_mmu_clear(); + dsp_err_clear(ERRCODE_MMU); return 0; } +#endif /* CONFIG_ARCH_OMAP1 */ + +#ifdef CONFIG_ARCH_OMAP2 +#define MMU_IRQ_MASK \ + (DSP_MMU_IRQ_MULTIHITFAULT | \ + DSP_MMU_IRQ_TABLEWALKFAULT | \ + DSP_MMU_IRQ_EMUMISS | \ + DSP_MMU_IRQ_TRANSLATIONFAULT | \ + DSP_MMU_IRQ_TLBMISS) +#endif static void dsp_mmu_init(void) { - unsigned long phys; - void *virt; + struct tlb_lock tlb_lock; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(dsp_ck_handle); + omap_dsp_request_mem(); +#endif down_write(&exmap_sem); +#if defined(CONFIG_ARCH_OMAP1) dsp_mmu_disable(); /* clear all */ udelay(100); +#elif defined(CONFIG_ARCH_OMAP2) + dsp_mmu_reset(); +#endif dsp_mmu_enable(); - /* mapping for ARM MMU */ - phys = __pa(dspvect_page); - virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */ - exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); - exmap_tbl[0].buf = dspvect_page; - exmap_tbl[0].vadr = virt; - exmap_tbl[0].usecount = 0; - exmap_tbl[0].order = 0; - exmap_tbl[0].valid = 1; - exmap_tbl[0].cntnu = 0; - /* DSP TLB initialization */ - set_tlb_lock(0, 0); - /* preserved, full access */ - dsp_mmu_load_tlb(DSP_INIT_PAGE, phys, DSPMMU_CAM_L_SLST_4KB, - DSPMMU_CAM_L_P, DSPMMU_RAM_L_AP_FA); + tlb_lock.base = 0; + tlb_lock.victim = 0; + set_tlb_lock(&tlb_lock); + + exmap_preserved_cnt = exmap_setup_preserved_entries(); + +#ifdef CONFIG_ARCH_OMAP2 + /* MMU IRQ mask setup */ + dsp_mmu_write_reg(MMU_IRQ_MASK, DSP_MMU_IRQENABLE); +#endif + up_write(&exmap_sem); +#ifdef CONFIG_ARCH_OMAP1 + omap_dsp_release_mem(); clk_disable(dsp_ck_handle); +#endif } static void dsp_mmu_shutdown(void) { exmap_flush(); - dsp_mmu_disable(); /* clear all */ + exmap_clear_preserved_entries(); + dsp_mmu_disable(); } +#ifdef CONFIG_ARCH_OMAP1 /* * intmem_enable() / disable(): * if the address is in DSP internal memories, @@ -1317,31 +1702,34 @@ static int intmem_enable(void) { int ret = 0; - if (dsp_is_ready()) - ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE, - DSPREG_ICR_DMA_IDLE_DOMAIN); + 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_is_ready()) - dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, - DSPREG_ICR_DMA_IDLE_DOMAIN); + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA); } +#endif /* CONFIG_ARCH_OMAP1 */ /* * dsp_mem_enable() / disable() */ +#ifdef CONFIG_ARCH_OMAP1 int intmem_usecount; +#endif int dsp_mem_enable(void *adr) { int ret = 0; if (is_dsp_internal_mem(adr)) { +#ifdef CONFIG_ARCH_OMAP1 if (intmem_usecount++ == 0) ret = omap_dsp_request_mem(); +#endif } else down_read(&exmap_sem); @@ -1351,13 +1739,16 @@ int dsp_mem_enable(void *adr) void dsp_mem_disable(void *adr) { if (is_dsp_internal_mem(adr)) { +#ifdef CONFIG_ARCH_OMAP1 if (--intmem_usecount == 0) omap_dsp_release_mem(); +#endif } else up_read(&exmap_sem); } /* for safety */ +#ifdef CONFIG_ARCH_OMAP1 void dsp_mem_usecount_clear(void) { if (intmem_usecount != 0) { @@ -1369,6 +1760,7 @@ void dsp_mem_usecount_clear(void) omap_dsp_release_mem(); } } +#endif /* CONFIG_ARCH_OMAP1 */ /* * dsp_mem file operations @@ -1394,7 +1786,7 @@ static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig) return ret; } -static ssize_t intmem_read(struct file *file, char *buf, size_t count, +static ssize_t intmem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; @@ -1404,7 +1796,9 @@ static ssize_t intmem_read(struct file *file, char *buf, size_t count, if (p >= size) return 0; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(api_ck_handle); +#endif read = count; if (count > size - p) read = size - p; @@ -1414,11 +1808,13 @@ static ssize_t intmem_read(struct file *file, char *buf, size_t count, } *ppos += read; out: +#ifdef CONFIG_ARCH_OMAP1 clk_disable(api_ck_handle); +#endif return read; } -static ssize_t exmem_read(struct file *file, char *buf, size_t count, +static ssize_t exmem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; @@ -1439,7 +1835,7 @@ static ssize_t exmem_read(struct file *file, char *buf, size_t count, return count; } -static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count, +static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret; @@ -1456,8 +1852,8 @@ static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count, return ret; } -static ssize_t intmem_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) +static ssize_t intmem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { unsigned long p = *ppos; void *vadr = dspbyte_to_virt(p); @@ -1466,7 +1862,9 @@ static ssize_t intmem_write(struct file *file, const char *buf, size_t count, if (p >= size) return 0; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(api_ck_handle); +#endif written = count; if (count > size - p) written = size - p; @@ -1476,12 +1874,14 @@ static ssize_t intmem_write(struct file *file, const char *buf, size_t count, } *ppos += written; out: +#ifdef CONFIG_ARCH_OMAP1 clk_disable(api_ck_handle); +#endif return written; } -static ssize_t exmem_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) +static ssize_t exmem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { unsigned long p = *ppos; void *vadr = dspbyte_to_virt(p); @@ -1501,8 +1901,8 @@ static ssize_t exmem_write(struct file *file, const char *buf, size_t count, return count; } -static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) +static ssize_t dsp_mem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { int ret; void *vadr = dspbyte_to_virt(*(unsigned long *)ppos); @@ -1522,51 +1922,56 @@ static int dsp_mem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { - case OMAP_DSP_MEM_IOCTL_MMUINIT: + case MEM_IOCTL_MMUINIT: dsp_mmu_init(); return 0; - case OMAP_DSP_MEM_IOCTL_EXMAP: + case MEM_IOCTL_EXMAP: { struct omap_dsp_mapinfo mapinfo; - if (copy_from_user(&mapinfo, (void *)arg, + if (copy_from_user(&mapinfo, (void __user *)arg, sizeof(mapinfo))) return -EFAULT; return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size, EXMAP_TYPE_MEM); } - case OMAP_DSP_MEM_IOCTL_EXUNMAP: + case MEM_IOCTL_EXUNMAP: return dsp_exunmap((unsigned long)arg); - case OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH: + case MEM_IOCTL_EXMAP_FLUSH: exmap_flush(); return 0; - case OMAP_DSP_MEM_IOCTL_FBEXPORT: + case MEM_IOCTL_FBEXPORT: { - unsigned long dspadr; + dsp_long_t dspadr; int ret; - if (copy_from_user(&dspadr, (void *)arg, sizeof(long))) + if (copy_from_user(&dspadr, (void __user *)arg, + sizeof(dsp_long_t))) return -EFAULT; ret = dsp_fbexport(&dspadr); - if (copy_to_user((void *)arg, &dspadr, sizeof(long))) + if (copy_to_user((void __user *)arg, &dspadr, + sizeof(dsp_long_t))) return -EFAULT; return ret; } - case OMAP_DSP_MEM_IOCTL_MMUITACK: +#ifdef CONFIG_ARCH_OMAP1 + case MEM_IOCTL_MMUITACK: return dsp_mmu_itack(); +#endif - case OMAP_DSP_MEM_IOCTL_KMEM_RESERVE: + case MEM_IOCTL_KMEM_RESERVE: { - unsigned long size; - if (copy_from_user(&size, (void *)arg, sizeof(long))) + __u32 size; + if (copy_from_user(&size, (void __user *)arg, + sizeof(__u32))) return -EFAULT; return dsp_kmem_reserve(size); } - case OMAP_DSP_MEM_IOCTL_KMEM_RELEASE: + case MEM_IOCTL_KMEM_RELEASE: dsp_kmem_release(); return 0; @@ -1591,17 +1996,12 @@ static int dsp_mem_open(struct inode *inode, struct file *file) return 0; } -static int dsp_mem_release(struct inode *inode, struct file *file) -{ - return 0; -} - #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL /* * fb update functions: * fbupd_response() is executed by the workqueue. * fbupd_cb() is called when fb update is done, in interrupt context. - * mbx1_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP. + * mbx_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP. */ static void fbupd_response(void *arg) { @@ -1625,7 +2025,7 @@ static void fbupd_cb(void *arg) schedule_work(&fbupd_response_work); } -void mbx1_fbctl_upd(void) +void mbx_fbctl_upd(void) { struct omapfb_update_window win; volatile unsigned short *buf = ipbuf_sys_da->d; @@ -1653,7 +2053,7 @@ void mbx1_fbctl_upd(void) #else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */ -void mbx1_fbctl_upd(void) +void mbx_fbctl_upd(void) { } #endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */ @@ -1661,72 +2061,130 @@ void mbx1_fbctl_upd(void) /* * sysfs files */ + +/* mmu */ static ssize_t mmu_show(struct device *dev, struct device_attribute *attr, char *buf) { int len; - int lbase, victim; + struct tlb_lock tlb_lock_org; int i; +#ifdef CONFIG_ARCH_OMAP1 clk_enable(dsp_ck_handle); + omap_dsp_request_mem(); +#endif down_read(&exmap_sem); - get_tlb_lock(&lbase, &victim); - - len = sprintf(buf, "p: preserved, v: valid\n" - "ety cam_va ram_pa sz ap\n"); - /* 00: p v 0x300000 0x10171800 64KB FA */ - for (i = 0; i < 32; i++) { - unsigned short cam_h, cam_l, ram_h, ram_l; - unsigned short cam_l_va_mask, prsvd, cam_vld, slst; - unsigned long cam_va; - unsigned short ram_l_ap; - unsigned long ram_pa; + get_tlb_lock(&tlb_lock_org); + +#if defined(CONFIG_ARCH_OMAP1) + len = sprintf(buf, "P: preserved, V: valid\n" + "ety P V size cam_va ram_pa ap\n"); + /* 00: P V 4KB 0x300000 0x10171800 FA */ +#elif defined(CONFIG_ARCH_OMAP2) + len = sprintf(buf, "P: preserved, V: valid\n" + "B: big endian, L:little endian, " + "M: mixed page attribute\n" + "ety P V size cam_va ram_pa E ES M\n"); + /* 00: P V 4KB 0x300000 0x10171800 B 16 M */ +#endif + + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { + struct cam_ram_regset cr; + struct tlb_lock tlb_lock_tmp; + struct tlb_entry ent; +#if defined(CONFIG_ARCH_OMAP1) char *pgsz_str, *ap_str; +#elif defined(CONFIG_ARCH_OMAP2) + char *pgsz_str, *elsz_str; +#endif /* read a TLB entry */ - __read_tlb(lbase, i, &cam_h, &cam_l, &ram_h, &ram_l); - - slst = cam_l & DSPMMU_CAM_L_SLST_MASK; - cam_l_va_mask = get_cam_l_va_mask(slst); - pgsz_str = (slst == DSPMMU_CAM_L_SLST_1MB) ? " 1MB": - (slst == DSPMMU_CAM_L_SLST_64KB)? "64KB": - (slst == DSPMMU_CAM_L_SLST_4KB) ? " 4KB": - " 1KB"; - prsvd = cam_l & DSPMMU_CAM_L_P; - cam_vld = cam_l & DSPMMU_CAM_L_V; - ram_l_ap = ram_l & DSPMMU_RAM_L_AP_MASK; - ap_str = (ram_l_ap == DSPMMU_RAM_L_AP_RO) ? "RO": - (ram_l_ap == DSPMMU_RAM_L_AP_FA) ? "FA": - "NA"; - cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 | - (unsigned long)(cam_l & cam_l_va_mask) << 6; - ram_pa = (unsigned long)ram_h << 16 | - (ram_l & DSPMMU_RAM_L_RAM_LSB_MASK); - - if (i == lbase) - len += sprintf(buf + len, "lock base = %d\n", lbase); - if (i == victim) - len += sprintf(buf + len, "victim = %d\n", victim); - /* 00: p v 0x300000 0x10171800 64KB FA */ + tlb_lock_tmp.base = tlb_lock_org.base; + tlb_lock_tmp.victim = i; + __read_tlb(&tlb_lock_tmp, &cr); + +#if defined(CONFIG_ARCH_OMAP1) + ent.pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK; + ent.prsvd = cr.cam_l & DSP_MMU_CAM_P; + ent.valid = cr.cam_l & DSP_MMU_CAM_V; + ent.ap = cr.ram_l & DSP_MMU_RAM_L_AP_MASK; + ent.va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 | + (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6; + ent.pa = (unsigned long)cr.ram_h << 16 | + (cr.ram_l & DSP_MMU_RAM_L_RAM_LSB_MASK); + + pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? " 1MB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? " 4KB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1KB) ? " 1KB": + " ???"; + ap_str = (ent.ap == DSP_MMU_RAM_L_AP_RO) ? "RO": + (ent.ap == DSP_MMU_RAM_L_AP_FA) ? "FA": + (ent.ap == DSP_MMU_RAM_L_AP_NA) ? "NA": + "??"; +#elif defined(CONFIG_ARCH_OMAP2) + ent.pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK; + ent.prsvd = cr.cam & DSP_MMU_CAM_P; + ent.valid = cr.cam & DSP_MMU_CAM_V; + ent.va = cr.cam & DSP_MMU_CAM_VATAG_MASK; + ent.endian = cr.ram & DSP_MMU_RAM_ENDIANNESS; + ent.elsz = cr.ram & DSP_MMU_RAM_ELEMENTSIZE_MASK; + ent.pa = cr.ram & DSP_MMU_RAM_PADDR_MASK; + ent.mixed = cr.ram & DSP_MMU_RAM_MIXED; + + pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? "64MB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? " 1MB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB": + (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? " 4KB": + " ???"; + elsz_str = (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_8) ? " 8": + (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_16) ? "16": + (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_32) ? "32": + "??"; +#endif + + if (i == tlb_lock_org.base) + len += sprintf(buf + len, "lock base = %d\n", + tlb_lock_org.base); + if (i == tlb_lock_org.victim) + len += sprintf(buf + len, "victim = %d\n", + tlb_lock_org.victim); +#if defined(CONFIG_ARCH_OMAP1) + len += sprintf(buf + len, + /* 00: P V 4KB 0x300000 0x10171800 FA */ + "%02d: %c %c %s 0x%06x 0x%08lx %s\n", + i, + ent.prsvd ? 'P' : ' ', + ent.valid ? 'V' : ' ', + pgsz_str, ent.va, ent.pa, ap_str); +#elif defined(CONFIG_ARCH_OMAP2) len += sprintf(buf + len, - "%02d: %c %c 0x%06lx 0x%08lx %s %s\n", + /* 00: P V 4KB 0x300000 0x10171800 B 16 M */ + "%02d: %c %c %s 0x%06x 0x%08lx %c %s %c\n", i, - prsvd ? 'p' : ' ', - cam_vld ? 'v' : ' ', - cam_va, ram_pa, pgsz_str, ap_str); + ent.prsvd ? 'P' : ' ', + ent.valid ? 'V' : ' ', + pgsz_str, ent.va, ent.pa, + ent.endian ? 'B' : 'L', + elsz_str, + ent.mixed ? 'M' : ' '); +#endif /* CONFIG_ARCH_OMAP2 */ } /* restore victim entry */ - set_tlb_lock(lbase, victim); + set_tlb_lock(&tlb_lock_org); up_read(&exmap_sem); +#ifdef CONFIG_ARCH_OMAP1 + omap_dsp_release_mem(); clk_disable(dsp_ck_handle); +#endif return len; } -static struct device_attribute dev_attr_mmu = __ATTR_RO(mmu); - +/* exmap */ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1734,128 +2192,208 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, int i; down_read(&exmap_sem); - len = sprintf(buf, "v: valid, c: cntnu\n" - "ety vadr buf od uc\n"); - /* 00: v c 0xe0300000 0xc0171800 0 */ - for (i = 0; i < DSPMMU_TLB_LINES; i++) { - struct exmap_tbl *ent = &exmap_tbl[i]; - /* 00: v c 0xe0300000 0xc0171800 0 */ - len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d %2d\n", - i, - ent->valid ? 'v' : ' ', - ent->cntnu ? 'c' : ' ', - ent->vadr, ent->buf, ent->order, ent->usecount); + len = sprintf(buf, " dspadr size buf size uc\n"); + /* 0x300000 0x123000 0xc0171000 0x100000 0*/ + for (i = 0; i < DSP_MMU_TLB_LINES; i++) { + struct exmap_tbl_entry *ent = &exmap_tbl[i]; + void *vadr; + unsigned long size; + enum exmap_type_e type; + int idx; + + /* find a top of link */ + if (!ent->valid || (ent->link.prev >= 0)) + continue; + + vadr = ent->vadr; + type = ent->type; + size = 0; + idx = i; + do { + ent = &exmap_tbl[idx]; + size += PAGE_SIZE << ent->order; + } while ((idx = ent->link.next) >= 0); + + len += sprintf(buf + len, "0x%06x %#8lx", + virt_to_dspbyte(vadr), size); + + if (type == EXMAP_TYPE_FB) { + len += sprintf(buf + len, " framebuf\n"); + } else { + len += sprintf(buf + len, "\n"); + idx = i; + do { + ent = &exmap_tbl[idx]; + len += sprintf(buf + len, + /* 0xc0171000 0x100000 0*/ + "%19s0x%8p %#8lx %2d\n", + "", ent->buf, + PAGE_SIZE << ent->order, + ent->usecount); + } while ((idx = ent->link.next) >= 0); + } } up_read(&exmap_sem); return len; } -static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap); - -static ssize_t kmem_pool_show(struct device *dev, - struct device_attribute *attr, char *buf) +/* mempool */ +static ssize_t mempool_show(struct device *dev, struct device_attribute *attr, + char *buf) { - int nr_1M, nr_64K, total; + int min_nr_1M = 0, curr_nr_1M = 0; + int min_nr_64K = 0, curr_nr_64K = 0; + int total = 0; - nr_1M = kmem_pool_1M->min_nr; - nr_64K = kmem_pool_64K->min_nr; - total = nr_1M * SZ_1MB + nr_64K * SZ_64KB; + if (likely(kmem_pool_1M)) { + min_nr_1M = kmem_pool_1M->min_nr; + curr_nr_1M = kmem_pool_1M->curr_nr; + total += min_nr_1M * SZ_1MB; + } + if (likely(kmem_pool_64K)) { + min_nr_64K = kmem_pool_64K->min_nr; + curr_nr_64K = kmem_pool_64K->curr_nr; + total += min_nr_64K * SZ_64KB; + } - return sprintf(buf, "0x%x %d %d\n", total, nr_1M, nr_64K); + return sprintf(buf, + "0x%x\n" + "1M buffer: %d (%d free)\n" + "64K buffer: %d (%d free)\n", + total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K); } -static struct device_attribute dev_attr_kmem_pool = __ATTR_RO(kmem_pool); - /* - * DSP MMU interrupt handler + * workqueue for mmu int */ - +#ifdef CONFIG_ARCH_OMAP1 /* * MMU fault mask: * We ignore prefetch err. */ #define MMUFAULT_MASK \ - (DSPMMU_FAULT_ST_PERM |\ - DSPMMU_FAULT_ST_TLB_MISS |\ - DSPMMU_FAULT_ST_TRANS) -irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned short status; - unsigned short adh, adl; - unsigned short dp; - - status = omap_readw(DSPMMU_FAULT_ST); - adh = omap_readw(DSPMMU_FAULT_AD_H); - adl = omap_readw(DSPMMU_FAULT_AD_L); - dp = adh & DSPMMU_FAULT_AD_H_DP; - dsp_fault_adr = MKLONG(adh & DSPMMU_FAULT_AD_H_ADR_MASK, adl); + (DSP_MMU_FAULT_ST_PERM |\ + DSP_MMU_FAULT_ST_TLB_MISS |\ + DSP_MMU_FAULT_ST_TRANS) +#endif /* CONFIG_ARCH_OMAP1 */ + +static void do_mmu_int(void) +{ +#if defined(CONFIG_ARCH_OMAP1) + + dsp_mmu_reg_t status; + dsp_mmu_reg_t adh, adl; + dsp_mmu_reg_t dp; + + status = dsp_mmu_read_reg(DSP_MMU_FAULT_ST); + adh = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_H); + adl = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_L); + dp = adh & DSP_MMU_FAULT_AD_H_DP; + dsp_fault_adr = MK32(adh & DSP_MMU_FAULT_AD_H_ADR_MASK, adl); + /* if the fault is masked, nothing to do */ if ((status & MMUFAULT_MASK) == 0) { printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n"); /* * note: in OMAP1710, * when CACHE + DMA domain gets out of idle in DSP, - * MMU interrupt occurs but DSPMMU_FAULT_ST is not set. + * MMU interrupt occurs but DSP_MMU_FAULT_ST is not set. * in this case, we just ignore the interrupt. */ if (status) { printk(KERN_DEBUG "%s%s%s%s\n", - (status & DSPMMU_FAULT_ST_PREF)? + (status & DSP_MMU_FAULT_ST_PREF)? " (prefetch err)" : "", - (status & DSPMMU_FAULT_ST_PERM)? + (status & DSP_MMU_FAULT_ST_PERM)? " (permission fault)" : "", - (status & DSPMMU_FAULT_ST_TLB_MISS)? + (status & DSP_MMU_FAULT_ST_TLB_MISS)? " (TLB miss)" : "", - (status & DSPMMU_FAULT_ST_TRANS) ? + (status & DSP_MMU_FAULT_ST_TRANS) ? " (translation fault)": ""); - printk(KERN_DEBUG - "fault address = %s: 0x%06lx\n", - dp ? "DATA" : "PROGRAM", + printk(KERN_DEBUG "fault address = %#08x\n", dsp_fault_adr); } - return IRQ_HANDLED; + enable_irq(INT_DSP_MMU); + return; } +#elif defined(CONFIG_ARCH_OMAP2) + + dsp_mmu_reg_t status; + + status = dsp_mmu_read_reg(DSP_MMU_IRQSTATUS); + dsp_fault_adr = dsp_mmu_read_reg(DSP_MMU_FAULT_AD); + +#endif /* CONFIG_ARCH_OMAP2 */ + printk(KERN_INFO "DSP MMU interrupt!\n"); + +#if defined(CONFIG_ARCH_OMAP1) + printk(KERN_INFO "%s%s%s%s\n", - (status & DSPMMU_FAULT_ST_PREF)? - (MMUFAULT_MASK & DSPMMU_FAULT_ST_PREF)? + (status & DSP_MMU_FAULT_ST_PREF)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PREF)? " prefetch err": " (prefetch err)": "", - (status & DSPMMU_FAULT_ST_PERM)? - (MMUFAULT_MASK & DSPMMU_FAULT_ST_PERM)? + (status & DSP_MMU_FAULT_ST_PERM)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PERM)? " permission fault": " (permission fault)": "", - (status & DSPMMU_FAULT_ST_TLB_MISS)? - (MMUFAULT_MASK & DSPMMU_FAULT_ST_TLB_MISS)? + (status & DSP_MMU_FAULT_ST_TLB_MISS)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TLB_MISS)? " TLB miss": " (TLB miss)": "", - (status & DSPMMU_FAULT_ST_TRANS)? - (MMUFAULT_MASK & DSPMMU_FAULT_ST_TRANS)? + (status & DSP_MMU_FAULT_ST_TRANS)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TRANS)? " translation fault": " (translation fault)": ""); - printk(KERN_INFO "fault address = %s: 0x%06lx\n", - dp ? "DATA" : "PROGRAM", - dsp_fault_adr); - if (dsp_is_ready()) { - /* - * If we call dsp_exmap() here, - * "kernel BUG at slab.c" occurs. - */ - /* FIXME */ - dsp_err_mmu_set(dsp_fault_adr); - } else { - disable_irq(INT_DSP_MMU); +#elif defined(CONFIG_ARCH_OMAP2) + + printk(KERN_INFO "%s%s%s%s%s\n", + (status & DSP_MMU_IRQ_MULTIHITFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_MULTIHITFAULT)? + " multi hit": + " (multi hit)": + "", + (status & DSP_MMU_IRQ_TABLEWALKFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TABLEWALKFAULT)? + " table walk fault": + " (table walk fault)": + "", + (status & DSP_MMU_IRQ_EMUMISS)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_EMUMISS)? + " EMU miss": + " (EMU miss)": + "", + (status & DSP_MMU_IRQ_TRANSLATIONFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TRANSLATIONFAULT)? + " translation fault": + " (translation fault)": + "", + (status & DSP_MMU_IRQ_TLBMISS)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TLBMISS)? + " TLB miss": + " (TLB miss)": + ""); + +#endif /* CONFIG_ARCH_OMAP2 */ + + printk(KERN_INFO "fault address = %#08x\n", dsp_fault_adr); + + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr); + else { +#ifdef CONFIG_ARCH_OMAP1 __dsp_mmu_itack(); +#endif printk(KERN_INFO "Resetting DSP...\n"); dsp_cpustat_request(CPUSTAT_RESET); - enable_irq(INT_DSP_MMU); /* * if we enable followings, semaphore lock should be avoided. * @@ -1865,6 +2403,26 @@ irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ } +#ifdef CONFIG_ARCH_OMAP2 + dsp_mmu_disable(); + dsp_mmu_write_reg(status, DSP_MMU_IRQSTATUS); + dsp_mmu_enable(); +#endif + + enable_irq(INT_DSP_MMU); +} + +static DECLARE_WORK(mmu_int_work, (void (*)(void *))do_mmu_int, NULL); + +/* + * DSP MMU interrupt handler + */ + +static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + disable_irq(INT_DSP_MMU); + schedule_work(&mmu_int_work); return IRQ_HANDLED; } @@ -1879,27 +2437,44 @@ struct file_operations dsp_mem_fops = { .ioctl = dsp_mem_ioctl, .mmap = dsp_mem_mmap, .open = dsp_mem_open, - .release = dsp_mem_release, }; void dsp_mem_start(void) { +#ifdef CONFIG_ARCH_OMAP1 dsp_register_mem_cb(intmem_enable, intmem_disable); +#endif } void dsp_mem_stop(void) { memset(&mem_sync, 0, sizeof(struct mem_sync_struct)); +#ifdef CONFIG_ARCH_OMAP1 dsp_unregister_mem_cb(); +#endif } +static char devid_mmu; + int __init dsp_mem_init(void) { int i; + int ret = 0; +#ifdef CONFIG_ARCH_OMAP2 + int dspmem_pg_count; - for (i = 0; i < DSPMMU_TLB_LINES; i++) { - exmap_tbl[i].valid = 0; + dspmem_pg_count = dspmem_size >> 12; + for (i = 0; i < dspmem_pg_count; i++) { + dsp_ipi_write_reg(i, DSP_IPI_INDEX); + dsp_ipi_write_reg(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY); } + dsp_ipi_write_reg(1, DSP_IPI_ENABLE); + + dsp_ipi_write_reg(IOMAP_VAL, DSP_IPI_IOMAP); +#endif + + for (i = 0; i < DSP_MMU_TLB_LINES; i++) + exmap_tbl[i].valid = 0; dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0); if (dspvect_page == NULL) { @@ -1909,34 +2484,59 @@ int __init dsp_mem_init(void) return -ENOMEM; } dsp_mmu_init(); +#ifdef CONFIG_ARCH_OMAP1 dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE); +#endif + + /* + * DSP MMU interrupt setup + */ + ret = request_irq(INT_DSP_MMU, dsp_mmu_interrupt, SA_INTERRUPT, "dsp", + &devid_mmu); + if (ret) { + printk(KERN_ERR + "failed to register DSP MMU interrupt: %d\n", ret); + goto fail; + } + + /* MMU interrupt is not enabled until DSP runs */ + disable_irq(INT_DSP_MMU); device_create_file(&dsp_device.dev, &dev_attr_mmu); device_create_file(&dsp_device.dev, &dev_attr_exmap); - device_create_file(&dsp_device.dev, &dev_attr_kmem_pool); + device_create_file(&dsp_device.dev, &dev_attr_mempool); return 0; + +fail: +#ifdef CONFIG_ARCH_OMAP1 + dsp_reset_idle_boot_base(); +#endif + dsp_mmu_shutdown(); + free_page((unsigned long)dspvect_page); + dspvect_page = NULL; + return ret; } void dsp_mem_exit(void) { + free_irq(INT_DSP_MMU, &devid_mmu); + + /* recover disable_depth */ + enable_irq(INT_DSP_MMU); + +#ifdef CONFIG_ARCH_OMAP1 + dsp_reset_idle_boot_base(); +#endif dsp_mmu_shutdown(); dsp_kmem_release(); if (dspvect_page != NULL) { - unsigned long virt; - - down_read(&exmap_sem); - - virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE); - flush_tlb_kernel_range(virt, virt + PAGE_SIZE); free_page((unsigned long)dspvect_page); dspvect_page = NULL; - - up_read(&exmap_sem); } device_remove_file(&dsp_device.dev, &dev_attr_mmu); device_remove_file(&dsp_device.dev, &dev_attr_exmap); - device_remove_file(&dsp_device.dev, &dev_attr_kmem_pool); + device_remove_file(&dsp_device.dev, &dev_attr_mempool); } diff --git a/arch/arm/plat-omap/dsp/error.c b/arch/arm/plat-omap/dsp/error.c index dd7d7c4594b..0213218d96e 100644 --- a/arch/arm/plat-omap/dsp/error.c +++ b/arch/arm/plat-omap/dsp/error.c @@ -1,52 +1,51 @@ /* - * linux/arch/arm/mach-omap/dsp/error.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP error detection I/F device driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/03/11: DSP Gateway version 3.3 */ #include -#include -#include #include #include #include #include #include -#include -#include -#include +#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 unsigned long errcode; static int errcnt; -static unsigned short wdtval; /* FIXME: read through ioctl */ -static unsigned long mmu_fadr; /* FIXME: read through ioctl */ +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 *buf, size_t count, +static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long flags; @@ -71,7 +70,7 @@ static ssize_t dsp_err_read(struct file *file, char *buf, size_t count, } local_irq_save(flags); - status = copy_to_user(buf, &errcode, 4); + status = copy_to_user(buf, &errval, 4); if (status) { local_irq_restore(flags); return -EFAULT; @@ -100,68 +99,86 @@ struct file_operations dsp_err_fops = { }; /* - * DSP MMU + * set / clear functions */ -void dsp_err_mmu_set(unsigned long adr) + +/* DSP MMU */ +static void dsp_err_mmu_set(unsigned long arg) { disable_irq(INT_DSP_MMU); - errcode |= OMAP_DSP_ERRDT_MMU; - errcnt++; - mmu_fadr = adr; - wake_up_interruptible(&err_wait_q); + mmu_fadr = (u32)arg; } -void dsp_err_mmu_clear(void) +static void dsp_err_mmu_clr(void) { - errcode &= ~OMAP_DSP_ERRDT_MMU; enable_irq(INT_DSP_MMU); } -int dsp_err_mmu_isset(void) +/* WDT */ +static void dsp_err_wdt_set(unsigned long arg) { - return (errcode & OMAP_DSP_ERRDT_MMU) ? 1 : 0; + wdtval = (u16)arg; } /* - * WDT + * error code handler */ -void dsp_err_wdt_clear(void) +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) { - errcode &= ~OMAP_DSP_ERRDT_WDT; + 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_wdt_isset(void) +int dsp_err_isset(enum errcode_e code) { - return (errcode & OMAP_DSP_ERRDT_WDT) ? 1 : 0; + return (errval & dsp_err_desc[code].val) ? 1 : 0; } /* - * functions called from mailbox1 interrupt routine + * functions called from mailbox interrupt routine */ -static void mbx1_err_wdt(unsigned short data) +static void mbx_err_wdt(u16 data) { - errcode |= OMAP_DSP_ERRDT_WDT; - errcnt++; - wdtval = data; - wake_up_interruptible(&err_wait_q); + dsp_err_set(DSP_ERR_WDT, (unsigned long)data); } #ifdef OLD_BINARY_SUPPORT /* v3.3 obsolete */ -void mbx1_wdt(struct mbcmd *mb) +void mbx_wdt(struct mbcmd *mb) { - mbx1_err_wdt(mb->data); + mbx_err_wdt(mb->data); } #endif -extern void mbx1_err_ipbfull(void); -extern void mbx1_err_fatal(unsigned char tid); +extern void mbx_err_ipbfull(void); +extern void mbx_err_fatal(u8 tid); -void mbx1_err(struct mbcmd *mb) +void mbx_err(struct mbcmd *mb) { - unsigned char eid = mb->cmd_l; + u8 eid = mb->cmd_l; char *eidnm = subcmd_name(mb); - unsigned char tid; + u8 tid; if (eidnm) { printk(KERN_WARNING @@ -173,17 +190,17 @@ void mbx1_err(struct mbcmd *mb) } switch (eid) { - case OMAP_DSP_EID_IPBFULL: - mbx1_err_ipbfull(); + case EID_IPBFULL: + mbx_err_ipbfull(); break; - case OMAP_DSP_EID_FATAL: + case EID_FATAL: tid = mb->data & 0x00ff; - mbx1_err_fatal(tid); + mbx_err_fatal(tid); break; - case OMAP_DSP_EID_WDT: - mbx1_err_wdt(mb->data); + case EID_WDT: + mbx_err_wdt(mb->data); break; } } @@ -193,11 +210,14 @@ void mbx1_err(struct mbcmd *mb) */ 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); + } + errcnt = 0; - if (dsp_err_wdt_isset()) - dsp_err_wdt_clear(); - if (dsp_err_mmu_isset()) - dsp_err_mmu_clear(); } void dsp_err_stop(void) diff --git a/arch/arm/plat-omap/dsp/fifo.h b/arch/arm/plat-omap/dsp/fifo.h index 46fc33ccc80..7fb7c1c9535 100644 --- a/arch/arm/plat-omap/dsp/fifo.h +++ b/arch/arm/plat-omap/dsp/fifo.h @@ -1,27 +1,24 @@ /* - * linux/arch/arm/mach-omap/dsp/fifo.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * FIFO buffer operators + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/02/24: DSP Gateway version 3.3 */ struct fifo_struct { @@ -53,8 +50,10 @@ static inline int init_fifo(struct fifo_struct *fifo, size_t sz) static inline void free_fifo(struct fifo_struct *fifo) { spin_lock(&fifo->lock); - if (fifo->buf == NULL) + if (fifo->buf == NULL) { + spin_unlock(&fifo->lock); return; + } kfree(fifo->buf); fifo->buf = NULL; @@ -87,25 +86,17 @@ static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz) kfree(fifo->buf); /* alloc */ - if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) { - fifo->sz = 0; - ret = -ENOMEM; - goto out; - } - fifo->sz = sz; - fifo->cnt = 0; - fifo->wp = 0; + ret = alloc_fifo(fifo, sz); out: spin_unlock(&fifo->lock); return ret; } -static inline void write_word_to_fifo(struct fifo_struct *fifo, - unsigned short word) +static inline void write_word_to_fifo(struct fifo_struct *fifo, u16 word) { spin_lock(&fifo->lock); - *(unsigned short *)&fifo->buf[fifo->wp] = word; + *(u16 *)&fifo->buf[fifo->wp] = word; if ((fifo->wp += 2) == fifo->sz) fifo->wp = 0; if ((fifo->cnt += 2) > fifo->sz) diff --git a/arch/arm/plat-omap/dsp/hardware_dsp.h b/arch/arm/plat-omap/dsp/hardware_dsp.h index 1308e530543..11efd301690 100644 --- a/arch/arm/plat-omap/dsp/hardware_dsp.h +++ b/arch/arm/plat-omap/dsp/hardware_dsp.h @@ -1,210 +1,34 @@ /* - * linux/arch/arm/mach-omap/dsp/hardware_dsp.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Register bit definitions for DSP driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/05/30: DSP Gateway version 3.3 */ #ifndef __OMAP_DSP_HARDWARE_DSP_H #define __OMAP_DSP_HARDWARE_DSP_H -#ifdef CONFIG_ARCH_OMAP15XX -#define OMAP1510_DARAM_BASE 0xe0000000 -#define OMAP1510_DARAM_SIZE 0x10000 -#define OMAP1510_SARAM_BASE 0xe0010000 -#define OMAP1510_SARAM_SIZE 0x18000 +#ifdef CONFIG_ARCH_OMAP1 +#include "omap1_dsp.h" #endif -#ifdef CONFIG_ARCH_OMAP16XX -#define OMAP16XX_DARAM_BASE 0xe0000000 -#define OMAP16XX_DARAM_SIZE 0x10000 -#define OMAP16XX_SARAM_BASE 0xe0010000 -#define OMAP16XX_SARAM_SIZE 0x18000 +#ifdef CONFIG_ARCH_OMAP2 +#include "omap2_dsp.h" #endif -/* - * MAJOR device number: !! allocated arbitrary !! - */ -#define OMAP_DSP_CTL_MAJOR 96 -#define OMAP_DSP_TASK_MAJOR 97 - -/* - * 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 MPUI_DSP_BOOT_CONFIG_DIRECT 0x00000000 -#define MPUI_DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001 -#define MPUI_DSP_BOOT_CONFIG_IDLE 0x00000002 -#define MPUI_DSP_BOOT_CONFIG_DL16 0x00000003 -#define MPUI_DSP_BOOT_CONFIG_DL32 0x00000004 -#define MPUI_DSP_BOOT_CONFIG_MPUI 0x00000005 -#define MPUI_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 MMU - */ -#define DSPMMU_BASE (0xfffed200) -#define DSPMMU_PREFETCH (DSPMMU_BASE + 0x00) -#define DSPMMU_WALKING_ST (DSPMMU_BASE + 0x04) -#define DSPMMU_CNTL (DSPMMU_BASE + 0x08) -#define DSPMMU_FAULT_AD_H (DSPMMU_BASE + 0x0c) -#define DSPMMU_FAULT_AD_L (DSPMMU_BASE + 0x10) -#define DSPMMU_FAULT_ST (DSPMMU_BASE + 0x14) -#define DSPMMU_IT_ACK (DSPMMU_BASE + 0x18) -#define DSPMMU_TTB_H (DSPMMU_BASE + 0x1c) -#define DSPMMU_TTB_L (DSPMMU_BASE + 0x20) -#define DSPMMU_LOCK (DSPMMU_BASE + 0x24) -#define DSPMMU_LD_TLB (DSPMMU_BASE + 0x28) -#define DSPMMU_CAM_H (DSPMMU_BASE + 0x2c) -#define DSPMMU_CAM_L (DSPMMU_BASE + 0x30) -#define DSPMMU_RAM_H (DSPMMU_BASE + 0x34) -#define DSPMMU_RAM_L (DSPMMU_BASE + 0x38) -#define DSPMMU_GFLUSH (DSPMMU_BASE + 0x3c) -#define DSPMMU_FLUSH_ENTRY (DSPMMU_BASE + 0x40) -#define DSPMMU_READ_CAM_H (DSPMMU_BASE + 0x44) -#define DSPMMU_READ_CAM_L (DSPMMU_BASE + 0x48) -#define DSPMMU_READ_RAM_H (DSPMMU_BASE + 0x4c) -#define DSPMMU_READ_RAM_L (DSPMMU_BASE + 0x50) - -#define DSPMMU_CNTL_BURST_16MNGT_EN 0x0020 -#define DSPMMU_CNTL_WTL_EN 0x0004 -#define DSPMMU_CNTL_MMU_EN 0x0002 -#define DSPMMU_CNTL_RESET_SW 0x0001 - -#define DSPMMU_FAULT_AD_H_DP 0x0100 -#define DSPMMU_FAULT_AD_H_ADR_MASK 0x00ff - -#define DSPMMU_FAULT_ST_PREF 0x0008 -#define DSPMMU_FAULT_ST_PERM 0x0004 -#define DSPMMU_FAULT_ST_TLB_MISS 0x0002 -#define DSPMMU_FAULT_ST_TRANS 0x0001 - -#define DSPMMU_IT_ACK_IT_ACK 0x0001 - -#define DSPMMU_LOCK_BASE_MASK 0xfc00 -#define DSPMMU_LOCK_BASE_SHIFT 10 -#define DSPMMU_LOCK_VICTIM_MASK 0x03f0 -#define DSPMMU_LOCK_VICTIM_SHIFT 4 - -#define DSPMMU_CAM_H_VA_TAG_H_MASK 0x0003 - -#define DSPMMU_CAM_L_VA_TAG_L1_MASK 0xc000 -#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB 0x0000 -#define DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB 0x3c00 -#define DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB 0x3fc0 -#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB 0x3ff0 -#define DSPMMU_CAM_L_P 0x0008 -#define DSPMMU_CAM_L_V 0x0004 -#define DSPMMU_CAM_L_SLST_MASK 0x0003 -#define DSPMMU_CAM_L_SLST_1MB 0x0000 -#define DSPMMU_CAM_L_SLST_64KB 0x0001 -#define DSPMMU_CAM_L_SLST_4KB 0x0002 -#define DSPMMU_CAM_L_SLST_1KB 0x0003 - -#define DSPMMU_RAM_L_RAM_LSB_MASK 0xfc00 -#define DSPMMU_RAM_L_AP_MASK 0x0300 -#define DSPMMU_RAM_L_AP_NA 0x0000 -#define DSPMMU_RAM_L_AP_RO 0x0200 -#define DSPMMU_RAM_L_AP_FA 0x0300 - -#define DSPMMU_GFLUSH_GFLUSH 0x0001 - -#define DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY 0x0001 - -#define DSPMMU_LD_TLB_RD 0x0002 -#define DSPMMU_LD_TLB_LD 0x0001 - -/* - * Mailbox - */ -#define MAILBOX_BASE (0xfffcf000) -#define MAILBOX_ARM2DSP1 (MAILBOX_BASE + 0x00) -#define MAILBOX_ARM2DSP1b (MAILBOX_BASE + 0x04) -#define MAILBOX_DSP2ARM1 (MAILBOX_BASE + 0x08) -#define MAILBOX_DSP2ARM1b (MAILBOX_BASE + 0x0c) -#define MAILBOX_DSP2ARM2 (MAILBOX_BASE + 0x10) -#define MAILBOX_DSP2ARM2b (MAILBOX_BASE + 0x14) -#define MAILBOX_ARM2DSP1_Flag (MAILBOX_BASE + 0x18) -#define MAILBOX_DSP2ARM1_Flag (MAILBOX_BASE + 0x1c) -#define MAILBOX_DSP2ARM2_Flag (MAILBOX_BASE + 0x20) - -/* - * DSP ICR - */ -#define DSPREG_ICR_RESERVED_BITS 0xffc0 -#define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020 -#define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010 -#define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008 -#define DSPREG_ICR_CACHE_IDLE_DOMAIN 0x0004 -#define DSPREG_ICR_DMA_IDLE_DOMAIN 0x0002 -#define DSPREG_ICR_CPU_IDLE_DOMAIN 0x0001 - #endif /* __OMAP_DSP_HARDWARE_DSP_H */ diff --git a/arch/arm/plat-omap/dsp/ioctl.h b/arch/arm/plat-omap/dsp/ioctl.h new file mode 100644 index 00000000000..f31dbd1aab8 --- /dev/null +++ b/arch/arm/plat-omap/dsp/ioctl.h @@ -0,0 +1,115 @@ +/* + * 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 + * + * 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 + * + */ + +/* + * for /dev/dspctl/ctl + */ +#define DSPCTL_IOCTL_RESET 1 +#define DSPCTL_IOCTL_RUN 2 +#define DSPCTL_IOCTL_SETRSTVECT 3 +#ifdef CONFIG_ARCH_OMAP1 +#define DSPCTL_IOCTL_CPU_IDLE 4 +#define DSPCTL_IOCTL_MPUI_WORDSWAP_ON 5 +#define DSPCTL_IOCTL_MPUI_WORDSWAP_OFF 6 +#define DSPCTL_IOCTL_MPUI_BYTESWAP_ON 7 +#define DSPCTL_IOCTL_MPUI_BYTESWAP_OFF 8 +#define DSPCTL_IOCTL_GBL_IDLE 9 +#endif /* CONFIG_ARCH_OMAP1 */ +#define DSPCTL_IOCTL_DSPCFG 10 +#define DSPCTL_IOCTL_DSPUNCFG 11 +#define DSPCTL_IOCTL_TASKCNT 12 +#define DSPCTL_IOCTL_POLL 13 +#define DSPCTL_IOCTL_REGMEMR 40 +#define DSPCTL_IOCTL_REGMEMW 41 +#define DSPCTL_IOCTL_REGIOR 42 +#define DSPCTL_IOCTL_REGIOW 43 +#define DSPCTL_IOCTL_GETVAR 44 +#define DSPCTL_IOCTL_SETVAR 45 +#define DSPCTL_IOCTL_RUNLEVEL 50 +#define DSPCTL_IOCTL_SUSPEND 51 +#define DSPCTL_IOCTL_RESUME 52 +#ifdef CONFIG_OMAP_DSP_FBEXPORT +#define DSPCTL_IOCTL_FBEN 53 +#define DSPCTL_IOCTL_FBDIS 54 +#endif /* CONFIG_OMAP_DSP_FBEXPORT */ +#define DSPCTL_IOCTL_MBSEND 99 + +struct omap_dsp_mailbox_cmd { + __u16 cmd; + __u16 data; +}; + +struct omap_dsp_reginfo { + __u16 adr; + __u16 val; +}; + +struct omap_dsp_varinfo { + __u8 varid; + __u16 val[0]; +}; + +/* + * for taskdev + * (ioctls below should be >= 0x10000) + */ +#define TASK_IOCTL_BFLSH 0x10000 +#define TASK_IOCTL_SETBSZ 0x10001 +#define TASK_IOCTL_LOCK 0x10002 +#define TASK_IOCTL_UNLOCK 0x10003 +#define TASK_IOCTL_GETNAME 0x10004 + +/* + * for /dev/dspctl/mem + */ +#define MEM_IOCTL_EXMAP 1 +#define MEM_IOCTL_EXUNMAP 2 +#define MEM_IOCTL_EXMAP_FLUSH 3 +#define MEM_IOCTL_FBEXPORT 5 +#ifdef CONFIG_ARCH_OMAP1 +#define MEM_IOCTL_MMUITACK 7 +#endif +#define MEM_IOCTL_MMUINIT 9 +#define MEM_IOCTL_KMEM_RESERVE 11 +#define MEM_IOCTL_KMEM_RELEASE 12 + +struct omap_dsp_mapinfo { + __u32 dspadr; + __u32 size; +}; + +/* + * for /dev/dspctl/twch + */ +#define TWCH_IOCTL_MKDEV 1 +#define TWCH_IOCTL_RMDEV 2 +#define TWCH_IOCTL_TADD 11 +#define TWCH_IOCTL_TDEL 12 +#define TWCH_IOCTL_TKILL 13 + +struct omap_dsp_taddinfo { + __u8 minor; + __u32 taskadr; +}; + +#define TADD_ABORTADR 0xffffffff diff --git a/arch/arm/plat-omap/dsp/ipbuf.c b/arch/arm/plat-omap/dsp/ipbuf.c index ebb482b05f0..b2c870982b6 100644 --- a/arch/arm/plat-omap/dsp/ipbuf.c +++ b/arch/arm/plat-omap/dsp/ipbuf.c @@ -1,57 +1,57 @@ /* - * linux/arch/arm/mach-omap/dsp/ipbuf.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * IPBUF handler + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/06: DSP Gateway version 3.3 */ -#include #include -#include -#include #include -#include -#include +#include +#include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" -struct ipbuf **ipbuf; +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(&dsp_device.dev, &dev_attr_ipbuf); + spin_lock(&ipb_free.lock); - INIT_IPBLINK(&ipb_free); + RESET_IPBLINK(&ipb_free); spin_unlock(&ipb_free.lock); ipbcfg.ln = 0; - if (ipbuf) { - kfree(ipbuf); - ipbuf = NULL; + 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); @@ -59,9 +59,9 @@ void ipbuf_stop(void) ipbuf_sys_hold_mem_active = 0; } -int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) +int ipbuf_config(u16 ln, u16 lsz, void *base) { - unsigned long lsz_byte = ((unsigned long)lsz) << 1; + size_t lsz_byte = ((size_t)lsz) << 1; size_t size; int ret = 0; int i; @@ -79,8 +79,8 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) if (dsp_address_validate(base, size, "global ipbuf") < 0) return -EINVAL; - ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL); - if (ipbuf == NULL) { + 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; @@ -90,7 +90,8 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) top = base + (sizeof(struct ipbuf) + lsz_byte) * i; btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1; - ipbuf[i] = (struct ipbuf *)top; + g_ipbuf[i].p = (struct ipbuf *)top; + g_ipbuf[i].bid = i; if (((unsigned long)top & 0xfffe0000) != ((unsigned long)btm & 0xfffe0000)) { /* @@ -99,7 +100,7 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) */ printk(KERN_ERR "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n" - " @0x%p, size=0x%08lx\n", i, top, lsz_byte); + " @0x%p, size=0x%08x\n", i, top, lsz_byte); ret = -EINVAL; goto free_out; } @@ -115,15 +116,17 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) " %d words * %d lines at 0x%p.\n", ipbcfg.lsz, ipbcfg.ln, ipbcfg.base); + device_create_file(&dsp_device.dev, &dev_attr_ipbuf); + return ret; free_out: - kfree(ipbuf); - ipbuf = NULL; + kfree(g_ipbuf); + g_ipbuf = NULL; return ret; } -int ipbuf_sys_config(void *p, enum arm_dsp_dir dir) +int ipbuf_sys_config(void *p, enum arm_dsp_dir_e dir) { char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D"; @@ -158,7 +161,7 @@ int ipbuf_sys_config(void *p, enum arm_dsp_dir dir) return 0; } -int ipbuf_p_validate(void *p, enum arm_dsp_dir dir) +int ipbuf_p_validate(void *p, enum arm_dsp_dir_e dir) { char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D"; @@ -175,57 +178,60 @@ int ipbuf_p_validate(void *p, enum arm_dsp_dir dir) /* * Global IPBUF operations */ -unsigned short get_free_ipbuf(unsigned char tid) +struct ipbuf_head *bid_to_ipbuf(u16 bid) { - unsigned short 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 OMAP_DSP_BID_NULL; + return NULL; spin_lock(&ipb_free.lock); if (ipblink_empty(&ipb_free)) { /* FIXME: wait on queue when not available. */ - bid = OMAP_DSP_BID_NULL; + ipb_h = NULL; goto out; } - bid = ipb_free.top; - ipbuf[bid]->la = tid; /* lock */ - ipblink_del_top(&ipb_free, ipbuf); + 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 bid; + return ipb_h; } -void release_ipbuf(unsigned short bid) +void release_ipbuf(struct ipbuf_head *ipb_h) { - if (ipbuf[bid]->la == OMAP_DSP_TID_FREE) { + if (ipb_h->p->la == TID_FREE) { printk(KERN_WARNING "omapdsp: attempt to release unlocked IPBUF[%d].\n", - bid); + ipb_h->bid); /* * FIXME: re-calc bsycnt */ return; } - ipbuf[bid]->la = OMAP_DSP_TID_FREE; - ipbuf[bid]->sa = OMAP_DSP_TID_FREE; - spin_lock(&ipb_free.lock); - ipblink_add_tail(&ipb_free, bid, ipbuf); - spin_unlock(&ipb_free.lock); + ipb_h->p->la = TID_FREE; + ipb_h->p->sa = TID_FREE; + ipblink_add_tail(&ipb_free, ipb_h->bid); } -static int try_yld(unsigned short bid) +static int try_yld(struct ipbuf_head *ipb_h) { int status; - ipbuf[bid]->sa = OMAP_DSP_TID_ANON; - status = dsp_mbsend(MBCMD(BKYLD), 0, bid); + 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(bid); + release_ipbuf(ipb_h); return status; } @@ -239,12 +245,11 @@ static int try_yld(unsigned short bid) static void do_balance_ipbuf(void) { while (ipbcfg.bsycnt <= ipbcfg.ln / 4) { - unsigned short bid; + struct ipbuf_head *ipb_h; - bid = get_free_ipbuf(OMAP_DSP_TID_ANON); - if (bid == OMAP_DSP_BID_NULL) + if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL) return; - if (try_yld(bid) < 0) + if (try_yld(ipb_h) < 0) return; } } @@ -258,31 +263,31 @@ void balance_ipbuf(void) } /* for process context */ -void unuse_ipbuf(unsigned short bid) +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(bid); + release_ipbuf(ipb_h); } else { /* we have enough IPBUF lines. let's return this line to DSP. */ - ipbuf[bid]->la = OMAP_DSP_TID_ANON; - try_yld(bid); + ipb_h->p->la = TID_ANON; + try_yld(ipb_h); balance_ipbuf(); } } /* for interrupt context */ -void unuse_ipbuf_nowait(unsigned short bid) +void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h) { - release_ipbuf(bid); + release_ipbuf(ipb_h); balance_ipbuf(); } /* - * functions called from mailbox1 interrupt routine + * functions called from mailbox interrupt routine */ -void mbx1_err_ipbfull(void) +void mbx_err_ipbfull(void) { ipbcfg.cnt_full++; } @@ -294,12 +299,13 @@ static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr, char *buf) { int len = 0; - unsigned short bid; + u16 bid; for (bid = 0; bid < ipbcfg.ln; bid++) { - unsigned short la = ipbuf[bid]->la; - unsigned short ld = ipbuf[bid]->ld; - unsigned short c = ipbuf[bid]->c; + 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"); @@ -307,13 +313,13 @@ static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr, } len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n", - bid, ipbuf[bid]); - if (la == OMAP_DSP_TID_FREE) { + 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 == OMAP_DSP_TID_FREE) { + } else if (ld == TID_FREE) { len += sprintf(buf + len, " Linux->DSPtask[%d] " "(already read and now free for DSP)\n", @@ -333,7 +339,7 @@ static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr, len += sprintf(buf + len, "\nFree IPBUF link: "); spin_lock(&ipb_free.lock); - ipblink_for_each(bid, &ipb_free, ipbuf) { + ipblink_for_each(bid, &ipb_free) { len += sprintf(buf + len, "%d ", bid); } spin_unlock(&ipb_free.lock); @@ -344,5 +350,3 @@ static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr, finish: return len; } - -struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf); diff --git a/arch/arm/plat-omap/dsp/ipbuf.h b/arch/arm/plat-omap/dsp/ipbuf.h index 77826f443d2..9a6e3db103c 100644 --- a/arch/arm/plat-omap/dsp/ipbuf.h +++ b/arch/arm/plat-omap/dsp/ipbuf.h @@ -1,75 +1,78 @@ /* - * linux/arch/arm/mach-omap/dsp/ipbuf.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Header for IPBUF + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/05/17: DSP Gateway version 3.3 */ struct ipbuf { - unsigned short c; /* count */ - unsigned short next; /* link */ - unsigned short la; /* lock owner (ARM side) */ - unsigned short sa; /* sync word (ARM->DSP) */ - unsigned short ld; /* lock owner (DSP side) */ - unsigned short sd; /* sync word (DSP->ARM) */ + 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 { - unsigned short c; /* count */ - unsigned short s; /* sync word */ - unsigned short al; /* data address lower */ - unsigned short ah; /* data address upper */ + 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 { - unsigned short s; /* sync word */ - unsigned short d[31]; /* data */ + u16 s; /* sync word */ + u16 d[IPBUF_SYS_DLEN]; /* data */ }; struct ipbcfg { - unsigned short ln; - unsigned short lsz; + u16 ln; + u16 lsz; void *base; - unsigned short bsycnt; + u16 bsycnt; unsigned long cnt_full; /* count of IPBFULL error */ }; -extern struct ipbuf **ipbuf; +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) \ do { \ - disable_irq(INT_D2A_MB1); \ + disable_mbx_irq(mbx_dsp); \ (ipbcfg)->bsycnt++; \ - enable_irq(INT_D2A_MB1); \ + enable_mbx_irq(mbx_dsp); \ } while(0) #define ipb_bsycnt_dec(ipbcfg) \ do { \ - disable_irq(INT_D2A_MB1); \ + disable_mbx_irq(mbx_dsp); \ (ipbcfg)->bsycnt--; \ - enable_irq(INT_D2A_MB1); \ + enable_mbx_irq(mbx_dsp); \ } while(0) #define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base) @@ -77,58 +80,120 @@ extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; struct ipblink { spinlock_t lock; - unsigned short top; - unsigned short tail; + u16 top; + u16 tail; }; #define IPBLINK_INIT { \ .lock = SPIN_LOCK_UNLOCKED, \ - .top = OMAP_DSP_BID_NULL, \ - .tail = OMAP_DSP_BID_NULL, \ + .top = BID_NULL, \ + .tail = BID_NULL, \ } #define INIT_IPBLINK(link) \ do { \ spin_lock_init(&(link)->lock); \ - (link)->top = OMAP_DSP_BID_NULL; \ - (link)->tail = OMAP_DSP_BID_NULL; \ + (link)->top = BID_NULL; \ + (link)->tail = BID_NULL; \ } while(0) -#define ipblink_empty(link) ((link)->top == OMAP_DSP_BID_NULL) +#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 **ipbuf) +static __inline__ void __ipblink_del_top(struct ipblink *link) { - struct ipbuf *bufp = ipbuf[link->top]; + struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top); - if ((link->top = bufp->next) == OMAP_DSP_BID_NULL) - link->tail = OMAP_DSP_BID_NULL; + if ((link->top = ipb_h->p->next) == BID_NULL) + link->tail = BID_NULL; else - bufp->next = OMAP_DSP_BID_NULL; + ipb_h->p->next = BID_NULL; } -static __inline__ void ipblink_add_tail(struct ipblink *link, - unsigned short bid, - struct ipbuf **ipbuf) +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 - ipbuf[link->tail]->next = bid; + 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) { - link->top = OMAP_DSP_BID_PVT; - link->tail = OMAP_DSP_BID_PVT; + 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) { - link->top = OMAP_DSP_BID_NULL; - link->tail = OMAP_DSP_BID_NULL; + 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, ipbuf) \ - for (bid = (link)->top; bid != OMAP_DSP_BID_NULL; bid = ipbuf[bid]->next) +#define ipblink_for_each(bid, link) \ + for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next) diff --git a/arch/arm/plat-omap/dsp/mblog.c b/arch/arm/plat-omap/dsp/mblog.c index 32989766020..4a4152dc929 100644 --- a/arch/arm/plat-omap/dsp/mblog.c +++ b/arch/arm/plat-omap/dsp/mblog.c @@ -1,115 +1,101 @@ /* - * linux/arch/arm/mach-omap/dsp/mblog.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP driver Mailbox log module + * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2003-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/05/18: DSP Gateway version 3.3 */ -#include -#include #include #include -#include -#include +#include +#include "dsp_mbcmd.h" #include "dsp.h" -#define RLCMD(nm) OMAP_DSP_MBCMD_RUNLEVEL_##nm -#define KFUNCCMD(nm) OMAP_DSP_MBCMD_KFUNC_##nm -#define PMCMD(nm) OMAP_DSP_MBCMD_PM_##nm -#define CFGCMD(nm) OMAP_DSP_MBCMD_DSPCFG_##nm -#define REGCMD(nm) OMAP_DSP_MBCMD_REGRW_##nm -#define VICMD(nm) OMAP_DSP_MBCMD_VARID_##nm -#define EID(nm) OMAP_DSP_EID_##nm - char *subcmd_name(struct mbcmd *mb) { - unsigned char cmd_h = mb->cmd_h; - unsigned char cmd_l = mb->cmd_l; + u8 cmd_h = mb->cmd_h; + u8 cmd_l = mb->cmd_l; char *s; switch (cmd_h) { - case MBCMD(RUNLEVEL): - s = (cmd_l == RLCMD(USER)) ? "USER": - (cmd_l == RLCMD(SUPER)) ? "SUPER": - (cmd_l == RLCMD(RECOVERY)) ? "RECOVERY": + case MBX_CMD_DSP_RUNLEVEL: + s = (cmd_l == RUNLEVEL_USER) ? "USER": + (cmd_l == RUNLEVEL_SUPER) ? "SUPER": + (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY": NULL; break; - case MBCMD(PM): - s = (cmd_l == PMCMD(DISABLE)) ? "DISABLE": - (cmd_l == PMCMD(ENABLE)) ? "ENABLE": + case MBX_CMD_DSP_PM: + s = (cmd_l == PM_DISABLE) ? "DISABLE": + (cmd_l == PM_ENABLE) ? "ENABLE": NULL; break; - case MBCMD(KFUNC): - s = (cmd_l == KFUNCCMD(FBCTL)) ? "FBCTL": - (cmd_l == KFUNCCMD(AUDIO_PWR)) ? "AUDIO_PWR": + case MBX_CMD_DSP_KFUNC: + s = (cmd_l == KFUNC_FBCTL) ? "FBCTL": NULL; break; - case MBCMD(DSPCFG): + case MBX_CMD_DSP_DSPCFG: { - unsigned char cfgc = cmd_l & 0x7f; - s = (cfgc == CFGCMD(REQ)) ? "REQ": - (cfgc == CFGCMD(SYSADRH)) ? "SYSADRH": - (cfgc == CFGCMD(SYSADRL)) ? "SYSADRL": - (cfgc == CFGCMD(ABORT)) ? "ABORT": - (cfgc == CFGCMD(PROTREV)) ? "PROTREV": + 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 MBCMD(REGRW): - s = (cmd_l == REGCMD(MEMR)) ? "MEMR": - (cmd_l == REGCMD(MEMW)) ? "MEMW": - (cmd_l == REGCMD(IOR)) ? "IOR": - (cmd_l == REGCMD(IOW)) ? "IOW": - (cmd_l == REGCMD(DATA)) ? "DATA": + case MBX_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 MBCMD(GETVAR): - case MBCMD(SETVAR): - s = (cmd_l == VICMD(ICRMASK)) ? "ICRMASK": - (cmd_l == VICMD(LOADINFO)) ? "LOADINFO": + case MBX_CMD_DSP_GETVAR: + case MBX_CMD_DSP_SETVAR: + s = (cmd_l == VARID_ICRMASK) ? "ICRMASK": + (cmd_l == VARID_LOADINFO) ? "LOADINFO": NULL; break; - case MBCMD(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": + case MBX_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: @@ -124,9 +110,8 @@ char *subcmd_name(struct mbcmd *mb) struct mblogent { unsigned long jiffies; - unsigned short cmd; - unsigned short data; - enum arm_dsp_dir dir; + mbx_msg_t msg; + enum arm_dsp_dir_e dir; }; static struct { @@ -134,19 +119,19 @@ static struct { int wp; unsigned long cnt, cnt_ad, cnt_da; struct mblogent ent[MBLOG_DEPTH]; -} mblog; +} mblog = { + .lock = SPIN_LOCK_UNLOCKED, +}; -void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir) +void mblog_add(struct mbcmd *mb, enum arm_dsp_dir_e dir) { - struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; struct mblogent *ent; spin_lock(&mblog.lock); ent = &mblog.ent[mblog.wp]; ent->jiffies = jiffies; - ent->cmd = mb_hw->cmd; - ent->data = mb_hw->data; - ent->dir = dir; + ent->msg = *(mbx_msg_t *)mb; + ent->dir = dir; if (mblog.cnt < 0xffffffff) mblog.cnt++; switch (dir) { @@ -183,36 +168,39 @@ static ssize_t mblog_show(struct device *dev, struct device_attribute *attr, if (mblog.cnt == 0) goto done; - len += sprintf(buf + len, " ARM -> DSP ARM <- DSP\n"); - len += sprintf(buf + len, "jiffies q cmd data q cmd data\n"); + 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]; - union { - struct mbcmd sw; - struct mbcmd_hw hw; - } mb = { - .hw.cmd = ent->cmd, - .hw.data = ent->data - }; + struct mbcmd *mb = (struct mbcmd *)&ent->msg; char *subname; - const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h]; + 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 %d %04x %04x ": - "%08lx %d %04x %04x ", - ent->jiffies, mb.sw.seq, ent->cmd, ent->data); + "%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.sw)) == NULL) + 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.sw.cmd_l); + ci->name, mb->cmd_l); break; case CMD_L_TYPE_NULL: len += sprintf(buf + len, "%s\n", ci->name); @@ -232,33 +220,40 @@ done: static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog); #ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE -void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir) +void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir_e dir) { - const struct cmdinfo *ci = cmdinfo[mb->cmd_h]; + struct cmdinfo ci_null = { + .name = "Unknown", + .cmd_l_type = CMD_L_TYPE_NULL, + }; + const struct cmdinfo *ci; char *dir_str; char *subname; dir_str = (dir == DIR_A2D) ? "sending" : "receiving"; + + 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"; printk(KERN_DEBUG - "mbx: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n", - dir_str, mb->seq, mb->cmd_h, mb->cmd_l, + "mbx: %s cmd=%02x:%02x(%s:%s), data=%04x\n", + dir_str, mb->cmd_h, mb->cmd_l, ci->name, subname, mb->data); break; case CMD_L_TYPE_TID: printk(KERN_DEBUG - "mbx: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n", - dir_str, mb->seq, mb->cmd_h, mb->cmd_l, + "mbx: %s cmd=%02x:%02x(%s:task %d), data=%04x\n", + dir_str, mb->cmd_h, mb->cmd_l, ci->name, mb->cmd_l, mb->data); break; case CMD_L_TYPE_NULL: printk(KERN_DEBUG - "mbx: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n", - dir_str, mb->seq, mb->cmd_h, mb->cmd_l, - ci->name, mb->data); + "mbx: %s cmd=%02x:%02x(%s), data=%04x\n", + dir_str, mb->cmd_h, mb->cmd_l, ci->name, mb->data); break; } } @@ -266,7 +261,6 @@ void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir) void __init mblog_init(void) { - spin_lock_init(&mblog.lock); device_create_file(&dsp_device.dev, &dev_attr_mblog); } diff --git a/arch/arm/plat-omap/dsp/omap1_dsp.h b/arch/arm/plat-omap/dsp/omap1_dsp.h new file mode 100644 index 00000000000..06a66faa48d --- /dev/null +++ b/arch/arm/plat-omap/dsp/omap1_dsp.h @@ -0,0 +1,188 @@ +/* + * 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 + * + * 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 MMU + */ +#define DSP_MMU_BASE (0xfffed200) +#define DSP_MMU_PREFETCH (DSP_MMU_BASE + 0x00) +#define DSP_MMU_WALKING_ST (DSP_MMU_BASE + 0x04) +#define DSP_MMU_CNTL (DSP_MMU_BASE + 0x08) +#define DSP_MMU_FAULT_AD_H (DSP_MMU_BASE + 0x0c) +#define DSP_MMU_FAULT_AD_L (DSP_MMU_BASE + 0x10) +#define DSP_MMU_FAULT_ST (DSP_MMU_BASE + 0x14) +#define DSP_MMU_IT_ACK (DSP_MMU_BASE + 0x18) +#define DSP_MMU_TTB_H (DSP_MMU_BASE + 0x1c) +#define DSP_MMU_TTB_L (DSP_MMU_BASE + 0x20) +#define DSP_MMU_LOCK (DSP_MMU_BASE + 0x24) +#define DSP_MMU_LD_TLB (DSP_MMU_BASE + 0x28) +#define DSP_MMU_CAM_H (DSP_MMU_BASE + 0x2c) +#define DSP_MMU_CAM_L (DSP_MMU_BASE + 0x30) +#define DSP_MMU_RAM_H (DSP_MMU_BASE + 0x34) +#define DSP_MMU_RAM_L (DSP_MMU_BASE + 0x38) +#define DSP_MMU_GFLUSH (DSP_MMU_BASE + 0x3c) +#define DSP_MMU_FLUSH_ENTRY (DSP_MMU_BASE + 0x40) +#define DSP_MMU_READ_CAM_H (DSP_MMU_BASE + 0x44) +#define DSP_MMU_READ_CAM_L (DSP_MMU_BASE + 0x48) +#define DSP_MMU_READ_RAM_H (DSP_MMU_BASE + 0x4c) +#define DSP_MMU_READ_RAM_L (DSP_MMU_BASE + 0x50) + +#define DSP_MMU_CNTL_BURST_16MNGT_EN 0x0020 +#define DSP_MMU_CNTL_WTL_EN 0x0004 +#define DSP_MMU_CNTL_MMU_EN 0x0002 +#define DSP_MMU_CNTL_RESET_SW 0x0001 + +#define DSP_MMU_FAULT_AD_H_DP 0x0100 +#define DSP_MMU_FAULT_AD_H_ADR_MASK 0x00ff + +#define DSP_MMU_FAULT_ST_PREF 0x0008 +#define DSP_MMU_FAULT_ST_PERM 0x0004 +#define DSP_MMU_FAULT_ST_TLB_MISS 0x0002 +#define DSP_MMU_FAULT_ST_TRANS 0x0001 + +#define DSP_MMU_IT_ACK_IT_ACK 0x0001 + +#define DSP_MMU_LOCK_BASE_MASK 0xfc00 +#define DSP_MMU_LOCK_BASE_SHIFT 10 +#define DSP_MMU_LOCK_VICTIM_MASK 0x03f0 +#define DSP_MMU_LOCK_VICTIM_SHIFT 4 + +#define DSP_MMU_CAM_H_VA_TAG_H_MASK 0x0003 + +#define DSP_MMU_CAM_L_VA_TAG_L1_MASK 0xc000 +#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB 0x0000 +#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB 0x3c00 +#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB 0x3fc0 +#define DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB 0x3ff0 +#define DSP_MMU_CAM_L_P 0x0008 +#define DSP_MMU_CAM_L_V 0x0004 +#define DSP_MMU_CAM_L_PAGESIZE_MASK 0x0003 +#define DSP_MMU_CAM_L_PAGESIZE_1MB 0x0000 +#define DSP_MMU_CAM_L_PAGESIZE_64KB 0x0001 +#define DSP_MMU_CAM_L_PAGESIZE_4KB 0x0002 +#define DSP_MMU_CAM_L_PAGESIZE_1KB 0x0003 + +#define DSP_MMU_RAM_L_RAM_LSB_MASK 0xfc00 +#define DSP_MMU_RAM_L_AP_MASK 0x0300 +#define DSP_MMU_RAM_L_AP_NA 0x0000 +#define DSP_MMU_RAM_L_AP_RO 0x0200 +#define DSP_MMU_RAM_L_AP_FA 0x0300 + +#define DSP_MMU_GFLUSH_GFLUSH 0x0001 + +#define DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY 0x0001 + +#define DSP_MMU_LD_TLB_RD 0x0002 +#define DSP_MMU_LD_TLB_LD 0x0001 + +/* + * 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 new file mode 100644 index 00000000000..3adf2b96fa0 --- /dev/null +++ b/arch/arm/plat-omap/dsp/omap2_dsp.h @@ -0,0 +1,158 @@ +/* + * 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 + * + * 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 +#include "../../mach-omap2/prcm-regs.h" + +/* + * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX() + */ +#define DSP_IPI_BASE DSP_IPI_24XX_VIRT +#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 MMU: mapped to 0xe2000000 -- use readX(), writeX() + */ +#define DSP_MMU_BASE DSP_MMU_24XX_VIRT +#define DSP_MMU_REVISION (DSP_MMU_BASE + 0x00) +#define DSP_MMU_SYSCONFIG (DSP_MMU_BASE + 0x10) +#define DSP_MMU_SYSSTATUS (DSP_MMU_BASE + 0x14) +#define DSP_MMU_IRQSTATUS (DSP_MMU_BASE + 0x18) +#define DSP_MMU_IRQENABLE (DSP_MMU_BASE + 0x1c) +#define DSP_MMU_WALKING_ST (DSP_MMU_BASE + 0x40) +#define DSP_MMU_CNTL (DSP_MMU_BASE + 0x44) +#define DSP_MMU_FAULT_AD (DSP_MMU_BASE + 0x48) +#define DSP_MMU_TTB (DSP_MMU_BASE + 0x4c) +#define DSP_MMU_LOCK (DSP_MMU_BASE + 0x50) +#define DSP_MMU_LD_TLB (DSP_MMU_BASE + 0x54) +#define DSP_MMU_CAM (DSP_MMU_BASE + 0x58) +#define DSP_MMU_RAM (DSP_MMU_BASE + 0x5c) +#define DSP_MMU_GFLUSH (DSP_MMU_BASE + 0x60) +#define DSP_MMU_FLUSH_ENTRY (DSP_MMU_BASE + 0x64) +#define DSP_MMU_READ_CAM (DSP_MMU_BASE + 0x68) +#define DSP_MMU_READ_RAM (DSP_MMU_BASE + 0x6c) +#define DSP_MMU_EMU_FAULT_AD (DSP_MMU_BASE + 0x70) + +#define DSP_MMU_SYSCONFIG_CLOCKACTIVITY_MASK 0x00000300 +#define DSP_MMU_SYSCONFIG_IDLEMODE_MASK 0x00000018 +#define DSP_MMU_SYSCONFIG_SOFTRESET 0x00000002 +#define DSP_MMU_SYSCONFIG_AUTOIDLE 0x00000001 + +#define DSP_MMU_IRQ_MULTIHITFAULT 0x00000010 +#define DSP_MMU_IRQ_TABLEWALKFAULT 0x00000008 +#define DSP_MMU_IRQ_EMUMISS 0x00000004 +#define DSP_MMU_IRQ_TRANSLATIONFAULT 0x00000002 +#define DSP_MMU_IRQ_TLBMISS 0x00000001 + +#define DSP_MMU_CNTL_EMUTLBUPDATE 0x00000008 +#define DSP_MMU_CNTL_TWLENABLE 0x00000004 +#define DSP_MMU_CNTL_MMUENABLE 0x00000002 + +#define DSP_MMU_LOCK_BASE_MASK 0x00007c00 +#define DSP_MMU_LOCK_BASE_SHIFT 10 +#define DSP_MMU_LOCK_VICTIM_MASK 0x000001f0 +#define DSP_MMU_LOCK_VICTIM_SHIFT 4 + +#define DSP_MMU_CAM_VATAG_MASK 0xfffff000 +#define DSP_MMU_CAM_P 0x00000008 +#define DSP_MMU_CAM_V 0x00000004 +#define DSP_MMU_CAM_PAGESIZE_MASK 0x00000003 +#define DSP_MMU_CAM_PAGESIZE_1MB 0x00000000 +#define DSP_MMU_CAM_PAGESIZE_64KB 0x00000001 +#define DSP_MMU_CAM_PAGESIZE_4KB 0x00000002 +#define DSP_MMU_CAM_PAGESIZE_16MB 0x00000003 + +#define DSP_MMU_RAM_PADDR_MASK 0xfffff000 +#define DSP_MMU_RAM_ENDIANNESS 0x00000200 +#define DSP_MMU_RAM_ENDIANNESS_BIG 0x00000200 +#define DSP_MMU_RAM_ENDIANNESS_LITTLE 0x00000000 +#define DSP_MMU_RAM_ELEMENTSIZE_MASK 0x00000180 +#define DSP_MMU_RAM_ELEMENTSIZE_8 0x00000000 +#define DSP_MMU_RAM_ELEMENTSIZE_16 0x00000080 +#define DSP_MMU_RAM_ELEMENTSIZE_32 0x00000100 +#define DSP_MMU_RAM_ELEMENTSIZE_NONE 0x00000180 +#define DSP_MMU_RAM_MIXED 0x00000040 + +#define DSP_MMU_GFLUSH_GFLUSH 0x00000001 + +#define DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY 0x00000001 + +#define DSP_MMU_LD_TLB_LD 0x00000001 + +/* + * 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 index 7265ea0fd4f..bf16b7c3f49 100644 --- a/arch/arm/plat-omap/dsp/proclist.h +++ b/arch/arm/plat-omap/dsp/proclist.h @@ -1,97 +1,78 @@ /* - * linux/arch/arm/mach-omap/dsp/proclist.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Linux task list handler + * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2004,2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2004/11/22: DSP Gateway version 3.3 */ struct proc_list { struct list_head list_head; pid_t pid; - unsigned int cnt; + struct file *file; }; -static __inline__ void proc_list_add(struct list_head *list, - struct task_struct *tsk) +static __inline__ void proc_list_add(spinlock_t *lock, struct list_head *list, + struct task_struct *tsk, struct file *file) { - struct proc_list *pl; struct proc_list *new; - list_for_each_entry(pl, list, list_head) { - if (pl->pid == tsk->pid) { - /* - * this process has opened DSP devices multi time - */ - pl->cnt++; - return; - } - } - new = kmalloc(sizeof(struct proc_list), GFP_KERNEL); new->pid = tsk->pid; - new->cnt = 1; + new->file = file; + spin_lock(lock); list_add_tail(&new->list_head, list); + spin_unlock(lock); } -static __inline__ void proc_list_del(struct list_head *list, - struct task_struct *tsk) +static __inline__ void proc_list_del(spinlock_t *lock, struct list_head *list, + struct task_struct *tsk, struct file *file) { - struct proc_list *pl, *next; + struct proc_list *pl; + spin_lock(lock); list_for_each_entry(pl, list, list_head) { - if (pl->pid == tsk->pid) { - if (--pl->cnt == 0) { - list_del(&pl->list_head); - kfree(pl); - } - return; - } - } - - /* - * correspinding pid wasn't found in the list - * -- this means the caller of proc_list_del is different from - * the proc_list_add's caller. in this case, the parent is - * cleaning up the context of a killed child. - * let's delete exiting task from the list. - */ - /* need to lock tasklist_lock before calling find_task_by_pid_type. */ - read_lock(&tasklist_lock); - list_for_each_entry_safe(pl, next, list, list_head) { - if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) == NULL) { + if (pl->file == file) { list_del(&pl->list_head); kfree(pl); + spin_unlock(lock); + return; } } - read_unlock(&tasklist_lock); + + /* 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(struct list_head *list) +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); } diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c index 9a9595d9d01..b6c7dfc9892 100644 --- a/arch/arm/plat-omap/dsp/task.c +++ b/arch/arm/plat-omap/dsp/task.c @@ -1,28 +1,24 @@ /* - * linux/arch/arm/mach-omap/dsp/task.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP task device driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi - * mmap function by Hiroo Ishikawa + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/07/26: DSP Gateway version 3.3 */ #include @@ -35,47 +31,80 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include +#include #include "uaccess_dsp.h" +#include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" #include "fifo.h" #include "proclist.h" +#include "ioctl.h" #define is_aligned(adr,align) (!((adr)&((align)-1))) /* - * taskdev.state: device state machine + * 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 devstate_name(stat) (\ - ((stat) & OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\ - ((stat) & OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\ - ((stat) & OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\ - ((stat) & OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\ - ((stat) & OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\ - ((stat) & OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\ - ((stat) & OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\ - ((stat) & OMAP_DSP_DEVSTATE_ADDING) ? "ADDING" :\ - ((stat) & OMAP_DSP_DEVSTATE_DELING) ? "DELING" :\ - ((stat) & OMAP_DSP_DEVSTATE_KILLING) ? "KILLING" :\ - "unknown") +#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 + +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; @@ -83,25 +112,35 @@ struct taskdev { struct device dev; /* Generic device interface */ long state; - spinlock_t state_lock; + struct rw_semaphore state_sem; wait_queue_head_t state_wait_q; + struct mutex usecount_mutex; unsigned int usecount; - char name[OMAP_DSP_TNM_LEN]; + 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; + union { + struct fifo_struct 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; - /* ioctl stuff */ - wait_queue_head_t ioctl_wait_q; - struct mutex ioctl_mutex; + /* 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; @@ -110,61 +149,71 @@ struct taskdev { #define to_taskdev(n) container_of(n, struct taskdev, dev) -struct rcvdt_bk_struct { - struct ipblink link; - unsigned int rp; - struct ipbuf_p *ipbuf_pvt_r; -}; - struct dsptask { enum { - TASK_STATE_ERR = 0, - TASK_STATE_READY, - TASK_STATE_CFGREQ + TASK_ST_ERR = 0, + TASK_ST_READY, + TASK_ST_CFGREQ } state; - unsigned char tid; - char name[OMAP_DSP_TNM_LEN]; - unsigned short ttyp; + u8 tid; + char name[TNM_LEN]; + u16 ttyp; struct taskdev *dev; /* read stuff */ - union { - struct fifo_struct fifo; /* for active word */ - struct rcvdt_bk_struct bk; - } rcvdt; + struct ipbuf_p *ipbuf_pvt_r; /* write stuff */ - size_t wsz; - spinlock_t wsz_lock; - struct ipbuf_p *ipbuf_pvt_w; /* for private block */ - - /* tctl stuff */ - int tctl_stat; + struct ipbuf_p *ipbuf_pvt_w; /* mmap stuff */ void *map_base; size_t map_length; }; -#define sndtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ASND) -#define sndtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ASND)) -#define sndtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKDM) -#define sndtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKDM)) -#define sndtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVDM) -#define sndtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVDM)) -#define rcvtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ARCV) -#define rcvtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ARCV)) -#define rcvtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKMD) -#define rcvtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKMD)) -#define rcvtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVMD) -#define rcvtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVMD)) - +#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 void taskdev_attach_task(struct taskdev *dev, struct dsptask *task); -static void taskdev_detach_task(struct taskdev *dev); -static int dsp_tdel_bh(unsigned char minor, unsigned short type); +static 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); @@ -189,147 +238,188 @@ static ssize_t wsz_show(struct device *d, struct device_attribute *attr, static ssize_t mmap_show(struct device *d, struct device_attribute *attr, char *buf); -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_fifosz = - __ATTR(fifosz, S_IWUGO | S_IRUGO, fifosz_show, fifosz_store); -static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt); -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_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 struct bus_type dsptask_bus = { - .name = "dsptask", -}; - -static struct class *dsp_task_class; -static struct taskdev *taskdev[TASKDEV_MAX]; -static struct dsptask *dsptask[TASKDEV_MAX]; -static DEFINE_MUTEX(cfg_lock); -static unsigned short cfg_cmd; -static unsigned char cfg_tid; -static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q); -static unsigned char n_task; -static void *heap; +#define __ATTR_RW(_name,_mode) { \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .show = _name##_show, \ + .store = _name##_store, \ +} -#define devstate_lock(dev, devstate) devstate_lock_timeout(dev, devstate, 0) +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); /* - * devstate_lock_timeout(): - * when called with timeout > 0, dev->state can be diffeent from what you want. + * devstate_read_lock_timeout() + * devstate_write_lock_timeout(): + * timeout != 0: dev->state can be diffeent from what you want. + * timeout == 0: no timeout */ -static int devstate_lock_timeout(struct taskdev *dev, long devstate, - int timeout) +static int devstate_read_lock_timeout(struct taskdev *dev, long devstate, + int timeout) { DECLARE_WAITQUEUE(wait, current); long current_state = current->state; int ret = 0; - spin_lock(&dev->state_lock); + down_read(&dev->state_sem); + if (dev->state & devstate) + return 0; + add_wait_queue(&dev->state_wait_q, &wait); - while (!(dev->state & devstate)) { + do { set_current_state(TASK_INTERRUPTIBLE); - spin_unlock(&dev->state_lock); + up_read(&dev->state_sem); if (timeout) { if ((timeout = schedule_timeout(timeout)) == 0) { /* timeout */ - spin_lock(&dev->state_lock); + down_read(&dev->state_sem); break; } + } else + schedule(); + if (signal_pending(current)) { + ret = -EINTR; + break; } - else + down_read(&dev->state_sem); + } while (!(dev->state & devstate)); + remove_wait_queue(&dev->state_wait_q, &wait); + set_current_state(current_state); + return ret; +} + +static int devstate_read_lock_and_test(struct taskdev *dev, long devstate) +{ + down_read(&dev->state_sem); + if (dev->state & devstate) + return 1; /* success */ + /* failure */ + up_read(&dev->state_sem); + return 0; +} + +static int devstate_write_lock_timeout(struct taskdev *dev, long devstate, + int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + long current_state = current->state; + int ret = 0; + + down_write(&dev->state_sem); + if (dev->state & devstate) + return 0; + + add_wait_queue(&dev->state_wait_q, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + up_write(&dev->state_sem); + if (timeout) { + if ((timeout = schedule_timeout(timeout)) == 0) { + /* timeout */ + down_write(&dev->state_sem); + break; + } + } else schedule(); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } - spin_lock(&dev->state_lock); - } + down_write(&dev->state_sem); + } while (!(dev->state & devstate)); remove_wait_queue(&dev->state_wait_q, &wait); set_current_state(current_state); return ret; } -static __inline__ void devstate_unlock(struct taskdev *dev) +static int devstate_write_lock_and_test(struct taskdev *dev, long devstate) { - spin_unlock(&dev->state_lock); + down_write(&dev->state_sem); + if (dev->state & devstate) /* success */ + return 1; + + /* failure */ + up_write(&dev->state_sem); + return -1; } -static inline int taskdev_lock_interruptible(struct taskdev *dev, - struct mutex *lock) +static int taskdev_lock_interruptible(struct taskdev *dev, struct mutex *mutex) { int ret; - if (dev->lock_pid == current->pid) { - /* this process has lock */ - ret = mutex_lock_interruptible(lock); - } else { + if (has_taskdev_lock(dev)) + ret = mutex_lock_interruptible(mutex); + else { if ((ret = mutex_lock_interruptible(&dev->lock)) != 0) return ret; - ret = mutex_lock_interruptible(lock); + ret = mutex_lock_interruptible(mutex); mutex_unlock(&dev->lock); } + return ret; } -static void proclist_send_sigbus(struct list_head *list) +static int taskdev_lock_and_statelock_attached(struct taskdev *dev, + struct mutex *mutex) { - siginfo_t info; - struct proc_list *pl; - struct task_struct *tsk; + int ret; - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = SI_KERNEL; - info._sifields._sigfault._addr = NULL; + if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED)) + return -ENODEV; - /* need to lock tasklist_lock before calling find_task_by_pid_type. */ - read_lock(&tasklist_lock); - list_for_each_entry(pl, list, list_head) { - if ((tsk = find_task_by_pid_type(PIDTYPE_PID, pl->pid)) != NULL) - send_sig_info(SIGBUS, &info, tsk); - } - read_unlock(&tasklist_lock); + if ((ret = taskdev_lock_interruptible(dev, mutex)) != 0) + devstate_read_unlock(dev); + + return ret; } -static int dsp_task_flush_buf(struct dsptask *task) +static __inline__ void taskdev_unlock_and_stateunlock(struct taskdev *dev, + struct mutex *mutex) +{ + mutex_unlock(mutex); + 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) { - unsigned short ttyp = task->ttyp; + u16 ttyp = dev->task->ttyp; if (sndtyp_wd(ttyp)) { /* word receiving */ - flush_fifo(&task->rcvdt.fifo); + flush_fifo(&dev->rcvdt.fifo); } else { /* block receiving */ - struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk; - - spin_lock(&rcvdt->link.lock); - if (sndtyp_gbl(ttyp)) { - /* global IPBUF */ - while (!ipblink_empty(&rcvdt->link)) { - unsigned short bid = rcvdt->link.top; - ipblink_del_top(&rcvdt->link, ipbuf); - unuse_ipbuf(bid); - } - } else { - /* private IPBUF */ - if (!ipblink_empty(&rcvdt->link)) { - ipblink_del_pvt(&rcvdt->link); - release_ipbuf_pvt(rcvdt->ipbuf_pvt_r); - } + 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); } - spin_unlock(&rcvdt->link.lock); } return 0; } -static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz) +/* + * taskdev_set_fifosz() + * must be called under dev->read_mutex. + */ +static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz) { - unsigned short ttyp = task->ttyp; + u16 ttyp = dev->task->ttyp; int stat; if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) { @@ -344,31 +434,36 @@ static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz) return -EINVAL; } - stat = realloc_fifo(&task->rcvdt.fifo, sz); + stat = realloc_fifo(&dev->rcvdt.fifo, sz); if (stat == -EBUSY) { printk(KERN_ERR "omapdsp: buffer is not empty!\n"); return stat; } else if (stat < 0) { printk(KERN_ERR "omapdsp: unable to change receive buffer size. " - "(%ld bytes for %s)\n", sz, task->name); + "(%ld bytes for %s)\n", sz, dev->name); return stat; } 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 -ERESTARTSYS; + return -EINTR; dev->lock_pid = current->pid; return 0; } static int taskdev_unlock(struct taskdev *dev) { - if (dev->lock_pid != current->pid) { + if (!has_taskdev_lock(dev)) { printk(KERN_ERR "omapdsp: an illegal process attempted to " "unlock the dsptask lock!\n"); @@ -379,28 +474,26 @@ static int taskdev_unlock(struct taskdev *dev) return 0; } -static int dsp_task_config(struct dsptask *task, unsigned char tid) +static int dsp_task_config(struct dsptask *task, u8 tid) { - unsigned short ttyp; - struct mbcmd mb; + u16 ttyp; int ret; task->tid = tid; dsptask[tid] = task; /* TCFG request */ - task->state = TASK_STATE_CFGREQ; + task->state = TASK_ST_CFGREQ; if (mutex_lock_interruptible(&cfg_lock)) { - ret = -ERESTARTSYS; + ret = -EINTR; goto fail_out; } - cfg_cmd = MBCMD(TCFG); - mbcmd_set(mb, MBCMD(TCFG), tid, 0); - dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q); + cfg_cmd = MBX_CMD_DSP_TCFG; + mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q); cfg_cmd = 0; mutex_unlock(&cfg_lock); - if (task->state != TASK_STATE_READY) { + if (task->state != TASK_ST_READY) { printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid); ret = -EINVAL; goto fail_out; @@ -426,7 +519,7 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) /* private buffer address check */ if (sndtyp_pvt(ttyp) && - (ipbuf_p_validate(task->rcvdt.bk.ipbuf_pvt_r, DIR_D2A) < 0)) { + (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) { ret = -EINVAL; goto fail_out; } @@ -451,36 +544,6 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) goto fail_out; } - /* - * initialization - */ - - /* read initialization */ - if (sndtyp_wd(ttyp)) { - /* word */ - size_t fifosz; - - fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */ - 32; /* active */ - if (init_fifo(&task->rcvdt.fifo, fifosz) < 0) { - printk(KERN_ERR - "omapdsp: unable to allocate receive buffer. " - "(%d bytes for %s)\n", fifosz, task->name); - ret = -ENOMEM; - goto fail_out; - } - } else { - /* block */ - INIT_IPBLINK(&task->rcvdt.bk.link); - task->rcvdt.bk.rp = 0; - } - - /* write initialization */ - spin_lock_init(&task->wsz_lock); - task->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */ - rcvtyp_wd(ttyp) ? 2 : /* passive word */ - ipbcfg.lsz*2; /* passive block */ - return 0; fail_out: @@ -490,10 +553,10 @@ fail_out: static void dsp_task_init(struct dsptask *task) { - dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT); + mbcompose_send(TCTL, task->tid, TCTL_TINIT); } -int dsp_task_config_all(unsigned char n) +int dsp_task_config_all(u8 n) { int i, ret; struct taskdev *devheap; @@ -503,26 +566,23 @@ int dsp_task_config_all(unsigned char n) memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX); memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX); - n_task = n; - printk(KERN_INFO "omapdsp: found %d task(s)\n", n_task); - if (n_task == 0) + printk(KERN_INFO "omapdsp: found %d task(s)\n", n); + if (n == 0) return 0; /* * reducing kmalloc! */ - devheapsz = sizeof(struct taskdev) * n_task; - taskheapsz = sizeof(struct dsptask) * n_task; - heap = kmalloc(devheapsz + taskheapsz, GFP_KERNEL); - if (heap == NULL) { - n_task = 0; + devheapsz = sizeof(struct taskdev) * n; + taskheapsz = sizeof(struct dsptask) * n; + heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL); + if (heap == NULL) return -ENOMEM; - } - memset(heap, 0, devheapsz + taskheapsz); devheap = heap; taskheap = heap + devheapsz; - for (i = 0; i < n_task; i++) { + n_task = n; + for (i = 0; i < n; i++) { struct taskdev *dev = &devheap[i]; struct dsptask *task = &taskheap[i]; @@ -530,7 +590,8 @@ int dsp_task_config_all(unsigned char n) return ret; if ((ret = taskdev_init(dev, task->name, i)) < 0) return ret; - taskdev_attach_task(dev, task); + if ((ret = taskdev_attach_task(dev, task)) < 0) + return ret; dsp_task_init(task); printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name); } @@ -540,20 +601,13 @@ int dsp_task_config_all(unsigned char n) static void dsp_task_unconfig(struct dsptask *task) { - unsigned char tid = task->tid; - - preempt_disable(); - dsp_task_flush_buf(task); - if (sndtyp_wd(task->ttyp) && (task->state == TASK_STATE_READY)) - free_fifo(&task->rcvdt.fifo); - dsptask[tid] = NULL; - preempt_enable(); + dsptask[task->tid] = NULL; } void dsp_task_unconfig_all(void) { unsigned char minor; - unsigned char tid; + u8 tid; struct dsptask *task; for (minor = 0; minor < n_task; minor++) { @@ -603,7 +657,7 @@ static struct device_driver dsptask_driver = { .bus = &dsptask_bus, }; -unsigned char dsp_task_count(void) +u8 dsp_task_count(void) { return n_task; } @@ -612,21 +666,22 @@ 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 (dev->usecount > 0) { + if ((usecount = dev->usecount) > 0) { printk("dsp_taskmod_busy(): %s: usecount=%d\n", - dev->name, dev->usecount); + dev->name, usecount); return 1; } /* - if ((dev->state & (OMAP_DSP_DEVSTATE_ADDREQ | - OMAP_DSP_DEVSTATE_DELREQ)) { + if ((dev->state & (TASKDEV_ST_ADDREQ | + TASKDEV_ST_DELREQ)) { */ - if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ) { + if (dev->state & TASKDEV_ST_ADDREQ) { printk("dsp_taskmod_busy(): %s is in %s\n", dev->name, devstate_name(dev->state)); return 1; @@ -638,12 +693,11 @@ int dsp_taskmod_busy(void) /* * DSP task device file operations */ -static ssize_t dsp_task_read_wd_acv(struct file *file, char *buf, size_t count, - loff_t *ppos) +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 have_devstate_lock = 0; int ret = 0; if (count == 0) { @@ -654,58 +708,40 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char *buf, size_t count, return -EINVAL; } - if (taskdev_lock_interruptible(dev, &dev->read_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; + if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex)) + return -ENODEV; - if (fifo_empty(&dev->task->rcvdt.fifo)) { + if (fifo_empty(&dev->rcvdt.fifo)) { long current_state = current->state; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&dev->read_wait_q, &wait); - if (fifo_empty(&dev->task->rcvdt.fifo)) { /* last check */ - devstate_unlock(dev); - have_devstate_lock = 0; + if (fifo_empty(&dev->rcvdt.fifo)) /* last check */ schedule(); - } set_current_state(current_state); remove_wait_queue(&dev->read_wait_q, &wait); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (fifo_empty(&dev->rcvdt.fifo)) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (!have_devstate_lock) { - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; - } - if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */ - goto up_out; } - ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count); + ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count); up_out: - if (have_devstate_lock) - devstate_unlock(dev); - mutex_unlock(&dev->read_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); return ret; } -static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, - loff_t *ppos) +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; - int have_devstate_lock = 0; + struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk; ssize_t ret = 0; if (count == 0) { @@ -721,55 +757,38 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, return -EINVAL; } - if (taskdev_lock_interruptible(dev, &dev->read_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; + if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex)) + return -ENODEV; - if (ipblink_empty(&dev->task->rcvdt.bk.link)) { + if (ipblink_empty(&rcvdt->link)) { long current_state; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&dev->read_wait_q, &wait); current_state = current->state; set_current_state(TASK_INTERRUPTIBLE); - if (ipblink_empty(&dev->task->rcvdt.bk.link)) { /* last check */ - devstate_unlock(dev); - have_devstate_lock = 0; + if (ipblink_empty(&rcvdt->link)) /* last check */ schedule(); - } set_current_state(current_state); remove_wait_queue(&dev->read_wait_q, &wait); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (ipblink_empty(&rcvdt->link)) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (!have_devstate_lock) { - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; - } - /* signal or 0-byte send from DSP */ - if (ipblink_empty(&dev->task->rcvdt.bk.link)) - goto up_out; } - rcvdt = &dev->task->rcvdt.bk; /* copy from delayed IPBUF */ if (sndtyp_pvt(dev->task->ttyp)) { /* private */ if (!ipblink_empty(&rcvdt->link)) { - struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r; unsigned char *base, *src; size_t bkcnt; if (dsp_mem_enable(ipbp) < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto up_out; } base = MKVIRT(ipbp->ah, ipbp->al); @@ -777,11 +796,11 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, if (dsp_address_validate(base, bkcnt, "task %s read buffer", dev->task->name) < 0) { - ret = -ERESTARTSYS; + ret = -EINVAL; goto pv_out1; } if (dsp_mem_enable(base) < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto pv_out1; } src = base + rcvdt->rp; @@ -798,9 +817,7 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, goto pv_out2; } ret = bkcnt; - spin_lock(&rcvdt->link.lock); ipblink_del_pvt(&rcvdt->link); - spin_unlock(&rcvdt->link.lock); release_ipbuf_pvt(ipbp); rcvdt->rp = 0; } @@ -812,17 +829,16 @@ pv_out1: } else { /* global */ if (dsp_mem_enable_ipbuf() < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto up_out; } while (!ipblink_empty(&rcvdt->link)) { unsigned char *src; size_t bkcnt; - unsigned short bid = rcvdt->link.top; - struct ipbuf *ipbp = ipbuf[bid]; + struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top); - src = ipbp->d + rcvdt->rp; - bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp; + 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; @@ -839,10 +855,8 @@ pv_out1: ret += bkcnt; buf += bkcnt; count -= bkcnt; - spin_lock(&rcvdt->link.lock); - ipblink_del_top(&rcvdt->link, ipbuf); - spin_unlock(&rcvdt->link.lock); - unuse_ipbuf(bid); + ipblink_del_top(&rcvdt->link); + unuse_ipbuf(ipb_h); rcvdt->rp = 0; } } @@ -851,19 +865,15 @@ gb_out: } up_out: - if (have_devstate_lock) - devstate_unlock(dev); - mutex_unlock(&dev->read_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); return ret; } -static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count, - loff_t *ppos) +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]; - struct mbcmd mb; - unsigned char tid; int ret = 0; if (count == 0) { @@ -877,46 +887,31 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count, count = 2; } - if (taskdev_lock_interruptible(dev, &dev->read_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - tid = dev->task->tid; - devstate_unlock(dev); + if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex)) + return -ENODEV; - mbcmd_set(mb, MBCMD(WDREQ), tid, 0); - dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q); + mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (fifo_empty(&dev->rcvdt.fifo)) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */ - goto unlock_out; - ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count); + ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count); -unlock_out: - devstate_unlock(dev); up_out: - mutex_unlock(&dev->read_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); return ret; } -static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, - loff_t *ppos) +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; - struct mbcmd mb; - unsigned char tid; + struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk; int ret = 0; if (count == 0) { @@ -932,53 +927,41 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, return -EINVAL; } - if (taskdev_lock_interruptible(dev, &dev->read_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - tid = dev->task->tid; - devstate_unlock(dev); + if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex)) + return -ENODEV; - mbcmd_set(mb, MBCMD(BKREQ), tid, count/2); - dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q); + mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2, + &dev->read_wait_q); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (ipblink_empty(&rcvdt->link)) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - rcvdt = &dev->task->rcvdt.bk; - /* signal or 0-byte send from DSP */ - if (ipblink_empty(&rcvdt->link)) - goto unlock_out; /* * We will not receive more than requested count. */ if (sndtyp_pvt(dev->task->ttyp)) { /* private */ - struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r; size_t rcvcnt; void *src; if (dsp_mem_enable(ipbp) < 0) { - ret = -ERESTARTSYS; - goto unlock_out; + 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 = -ERESTARTSYS; + ret = -EINVAL; goto pv_out1; } if (dsp_mem_enable(src) < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto pv_out1; } if (count > rcvcnt) @@ -987,9 +970,7 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, ret = -EFAULT; goto pv_out2; } - spin_lock(&rcvdt->link.lock); ipblink_del_pvt(&rcvdt->link); - spin_unlock(&rcvdt->link.lock); release_ipbuf_pvt(ipbp); ret = count; pv_out2: @@ -998,44 +979,38 @@ pv_out1: dsp_mem_disable(ipbp); } else { /* global */ - unsigned short bid = rcvdt->link.top; - struct ipbuf *ipbp = ipbuf[bid]; + struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top); size_t rcvcnt; if (dsp_mem_enable_ipbuf() < 0) { - ret = -ERESTARTSYS; - goto unlock_out; + ret = -EBUSY; + goto up_out; } - rcvcnt = ((unsigned long)ipbp->c) * 2; + rcvcnt = ((unsigned long)ipb_h->p->c) * 2; if (count > rcvcnt) count = rcvcnt; - if (copy_to_user_dsp(buf, ipbp->d, count)) { + if (copy_to_user_dsp(buf, ipb_h->p->d, count)) { ret = -EFAULT; goto gb_out; } - spin_lock(&rcvdt->link.lock); - ipblink_del_top(&rcvdt->link, ipbuf); - spin_unlock(&rcvdt->link.lock); - unuse_ipbuf(bid); + ipblink_del_top(&rcvdt->link); + unuse_ipbuf(ipb_h); ret = count; gb_out: dsp_mem_disable_ipbuf(); } -unlock_out: - devstate_unlock(dev); up_out: - mutex_unlock(&dev->read_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); return ret; } -static ssize_t dsp_task_write_wd(struct file *file, const char *buf, +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]; - unsigned short wd; - int have_devstate_lock = 0; + u16 wd; int ret = 0; if (count == 0) { @@ -1049,41 +1024,26 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf, count = 2; } - if (taskdev_lock_interruptible(dev, &dev->write_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; + if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex)) + return -ENODEV; - if (dev->task->wsz == 0) { + if (dev->wsz == 0) { long current_state; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&dev->write_wait_q, &wait); current_state = current->state; set_current_state(TASK_INTERRUPTIBLE); - if (dev->task->wsz == 0) { /* last check */ - devstate_unlock(dev); - have_devstate_lock = 0; + if (dev->wsz == 0) /* last check */ schedule(); - } set_current_state(current_state); remove_wait_queue(&dev->write_wait_q, &wait); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (dev->wsz == 0) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (!have_devstate_lock) { - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; - } - if (dev->task->wsz == 0) /* should not occur */ - goto up_out; } if (copy_from_user(&wd, buf, count)) { @@ -1091,29 +1051,26 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf, goto up_out; } - spin_lock(&dev->task->wsz_lock); - if (dsp_mbsend(MBCMD(WDSND), dev->task->tid, wd) < 0) { - spin_unlock(&dev->task->wsz_lock); + 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->task->wsz = 0; - spin_unlock(&dev->task->wsz_lock); + dev->wsz = 0; + spin_unlock(&dev->wsz_lock); up_out: - if (have_devstate_lock) - devstate_unlock(dev); - mutex_unlock(&dev->write_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->write_mutex); return ret; } -static ssize_t dsp_task_write_bk(struct file *file, const char *buf, +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 have_devstate_lock = 0; int ret = 0; if (count == 0) { @@ -1129,45 +1086,30 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, return -EINVAL; } - if (taskdev_lock_interruptible(dev, &dev->write_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; + if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex)) + return -ENODEV; - if (dev->task->wsz == 0) { + if (dev->wsz == 0) { long current_state; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&dev->write_wait_q, &wait); current_state = current->state; set_current_state(TASK_INTERRUPTIBLE); - if (dev->task->wsz == 0) { /* last check */ - devstate_unlock(dev); - have_devstate_lock = 0; + if (dev->wsz == 0) /* last check */ schedule(); - } set_current_state(current_state); remove_wait_queue(&dev->write_wait_q, &wait); - if (signal_pending(current)) { - ret = -ERESTARTSYS; + if (dev->wsz == 0) { + /* failure */ + if (signal_pending(current)) + ret = -EINTR; goto up_out; } - if (!have_devstate_lock) { - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - have_devstate_lock = 1; - } - if (dev->task->wsz == 0) /* should not occur */ - goto up_out; } - if (count > dev->task->wsz) - count = dev->task->wsz; + if (count > dev->wsz) + count = dev->wsz; if (rcvtyp_pvt(dev->task->ttyp)) { /* private */ @@ -1175,17 +1117,17 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, unsigned char *dst; if (dsp_mem_enable(ipbp) < 0) { - ret = -ERESTARTSYS; + 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 = -ERESTARTSYS; + ret = -EINVAL; goto pv_out1; } if (dsp_mem_enable(dst) < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto pv_out1; } if (copy_from_user_dsp(dst, buf, count)) { @@ -1194,54 +1136,49 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, } ipbp->c = count/2; ipbp->s = dev->task->tid; - spin_lock(&dev->task->wsz_lock); - if (dsp_mbsend(MBCMD(BKSNDP), dev->task->tid, 0) == 0) { + spin_lock(&dev->wsz_lock); + if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) { if (rcvtyp_acv(dev->task->ttyp)) - dev->task->wsz = 0; + dev->wsz = 0; ret = count; } - spin_unlock(&dev->task->wsz_lock); + spin_unlock(&dev->wsz_lock); pv_out2: dsp_mem_disable(dst); pv_out1: dsp_mem_disable(ipbp); } else { /* global */ - struct ipbuf *ipbp; - unsigned short bid; + struct ipbuf_head *ipb_h; if (dsp_mem_enable_ipbuf() < 0) { - ret = -ERESTARTSYS; + ret = -EBUSY; goto up_out; } - bid = get_free_ipbuf(dev->task->tid); - if (bid == OMAP_DSP_BID_NULL) + if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL) goto gb_out; - ipbp = ipbuf[bid]; - if (copy_from_user_dsp(ipbp->d, buf, count)) { - release_ipbuf(bid); + if (copy_from_user_dsp(ipb_h->p->d, buf, count)) { + release_ipbuf(ipb_h); ret = -EFAULT; goto gb_out; } - ipbp->c = count/2; - ipbp->sa = dev->task->tid; - spin_lock(&dev->task->wsz_lock); - if (dsp_mbsend(MBCMD(BKSND), dev->task->tid, bid) == 0) { + 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->task->wsz = 0; + dev->wsz = 0; ret = count; ipb_bsycnt_inc(&ipbcfg); } else - release_ipbuf(bid); - spin_unlock(&dev->task->wsz_lock); + release_ipbuf(ipb_h); + spin_unlock(&dev->wsz_lock); gb_out: dsp_mem_disable_ipbuf(); } up_out: - if (have_devstate_lock) - devstate_unlock(dev); - mutex_unlock(&dev->write_mutex); + taskdev_unlock_and_stateunlock(dev, &dev->write_mutex); return ret; } @@ -1252,78 +1189,42 @@ static unsigned int dsp_task_poll(struct file * file, poll_table * wait) 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 (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) - return 0; if (sndtyp_psv(task->ttyp) || - (sndtyp_wd(task->ttyp) && !fifo_empty(&task->rcvdt.fifo)) || - (sndtyp_bk(task->ttyp) && !ipblink_empty(&task->rcvdt.bk.link))) + (sndtyp_wd(task->ttyp) && !fifo_empty(&dev->rcvdt.fifo)) || + (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link))) mask |= POLLIN | POLLRDNORM; - if (task->wsz) + if (dev->wsz) mask |= POLLOUT | POLLWRNORM; - devstate_unlock(dev); + devstate_read_unlock(dev); return mask; } -static int dsp_task_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[]) { - unsigned int minor = MINOR(inode->i_rdev); - struct taskdev *dev = taskdev[minor]; - struct mbcmd mb; - unsigned char tid; + int tctl_argc; struct mb_exarg mbarg, *mbargp; - int mbargc; - unsigned short mbargv[1]; int interactive; - int ret; - - /* LOCK / UNLOCK operations */ - switch (cmd) { - case OMAP_DSP_TASK_IOCTL_LOCK: - return taskdev_lock(dev); - case OMAP_DSP_TASK_IOCTL_UNLOCK: - return taskdev_unlock(dev); - } - - /* - * actually only interractive commands need to lock - * the mutex, but here all commands do it for simplicity. - */ - if (taskdev_lock_interruptible(dev, &dev->ioctl_mutex)) - return -ERESTARTSYS; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } + u8 tid; + int ret = 0; - if ((cmd >= 0x0080) && (cmd < 0x0100)) { - /* - * 0x0080 - 0x00ff - * reserved for backward compatibility - * user-defined TCTL commands: no arg, non-interactive - */ - printk(KERN_WARNING "omapdsp: " - "TCTL commands in 0x0080 - 0x0100 are obsolete.\n" - "they won't be supported in the future.\n"); - mbargc = 0; - interactive = 0; - } else if (cmd < 0x8000) { + if (cmd < 0x8000) { /* - * 0x0000 - 0x7fff (except 0x0080 - 0x00ff) + * 0x0000 - 0x7fff * system reserved TCTL commands */ switch (cmd) { - case OMAP_DSP_MBCMD_TCTL_TEN: - case OMAP_DSP_MBCMD_TCTL_TDIS: - mbargc = 0; + case TCTL_TEN: + case TCTL_TDIS: + tctl_argc = 0; interactive = 0; break; default: - ret = -ENOIOCTLCMD; - goto unlock_out; + return -EINVAL; } } /* @@ -1332,94 +1233,123 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, */ else if (cmd < 0x8100) { /* 0x8000-0x80ff: no arg, non-interactive */ - mbargc = 0; + tctl_argc = 0; interactive = 0; } else if (cmd < 0x8200) { /* 0x8100-0x81ff: 1 arg, non-interactive */ - mbargc = 1; - mbargv[0] = arg & 0xffff; + tctl_argc = 1; interactive = 0; } else if (cmd < 0x9000) { /* 0x8200-0x8fff: reserved */ - ret = -ENOIOCTLCMD; - goto unlock_out; + return -EINVAL; } else if (cmd < 0x9100) { /* 0x9000-0x90ff: no arg, interactive */ - mbargc = 0; + tctl_argc = 0; interactive = 1; } else if (cmd < 0x9200) { /* 0x9100-0x91ff: 1 arg, interactive */ - mbargc = 1; - mbargv[0] = arg & 0xffff; + tctl_argc = 1; interactive = 1; - } else if (cmd < 0x10000) { - /* 0x9200-0xffff: reserved */ - ret = -ENOIOCTLCMD; - goto unlock_out; } else { - /* - * 0x10000 - - * non TCTL ioctls - */ - switch (cmd) { - case OMAP_DSP_TASK_IOCTL_BFLSH: - ret = dsp_task_flush_buf(dev->task); - break; - case OMAP_DSP_TASK_IOCTL_SETBSZ: - ret = dsp_task_set_fifosz(dev->task, arg); - break; - case OMAP_DSP_TASK_IOCTL_GETNAME: - ret = 0; - if (copy_to_user((void *)arg, dev->name, - strlen(dev->name) + 1)) - ret = -EFAULT; - break; - default: - ret = -ENOIOCTLCMD; - } - goto unlock_out; + /* 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; - mbcmd_set(mb, MBCMD(TCTL), tid, cmd); - if (mbargc > 0) { - mbarg.argc = mbargc; + if (tctl_argc > 0) { + mbarg.argc = tctl_argc; mbarg.tid = tid; - mbarg.argv = mbargv; + mbarg.argv = argv; mbargp = &mbarg; } else mbargp = NULL; if (interactive) { - dev->task->tctl_stat = -ERESTARTSYS; - devstate_unlock(dev); + dev->tctl_stat = -EINVAL; - dsp_mbcmd_send_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q); + mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp, + &dev->tctl_wait_q); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; goto up_out; } - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { - ret = -ERESTARTSYS; - goto up_out; - } - ret = dev->task->tctl_stat; - if (ret < 0) { + if ((ret = dev->tctl_stat) < 0) { printk(KERN_ERR "omapdsp: TCTL not responding.\n"); - goto unlock_out; + goto up_out; } - } else { - dsp_mbcmd_send_exarg(&mb, mbargp); + } 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; + } -unlock_out: - devstate_unlock(dev); -up_out: - mutex_unlock(&dev->ioctl_mutex); return ret; } @@ -1429,7 +1359,7 @@ static void dsp_task_mmap_open(struct vm_area_struct *vma) struct dsptask *task; size_t len = vma->vm_end - vma->vm_start; - BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)); + BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED)); task = dev->task; exmap_use(task->map_base, len); } @@ -1440,7 +1370,7 @@ static void dsp_task_mmap_close(struct vm_area_struct *vma) struct dsptask *task; size_t len = vma->vm_end - vma->vm_start; - BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)); + BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED)); task = dev->task; exmap_unuse(task->map_base, len); } @@ -1471,8 +1401,8 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) struct dsptask *task; int ret = 0; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) - return -ERESTARTSYS; + if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED)) + return -ENODEV; task = dev->task; /* @@ -1525,7 +1455,7 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) exmap_use(task->map_base, vma->vm_end - vma->vm_start); unlock_out: - devstate_unlock(dev); + devstate_read_unlock(dev); return ret; } @@ -1537,49 +1467,84 @@ static int dsp_task_open(struct inode *inode, struct file *file) if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) return -ENODEV; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK | - OMAP_DSP_DEVSTATE_ATTACHED) < 0) - return -ERESTARTSYS; -#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN - if (dev->usecount > 0) { - ret = -EBUSY; - goto unlock_out; - } -#endif - if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) { - dev->state = OMAP_DSP_DEVSTATE_ADDREQ; - /* wake up twch daemon for tadd */ - dsp_twch_touch(); - devstate_unlock(dev); - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED | - OMAP_DSP_DEVSTATE_ADDFAIL) < 0) { - spin_lock(&dev->state_lock); - if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ) - dev->state = OMAP_DSP_DEVSTATE_NOTASK; - spin_unlock(&dev->state_lock); - return -ERESTARTSYS; - } - if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) { - printk(KERN_ERR "omapdsp: task attach failed for %s!\n", - dev->name); - ret = -EBUSY; - dev->state = OMAP_DSP_DEVSTATE_NOTASK; - wake_up_interruptible_all(&dev->state_wait_q); - goto unlock_out; +restart: + mutex_lock(&dev->usecount_mutex); + 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_mutex); + return -ENODEV; + + case TASKDEV_ST_FREEZED: + case TASKDEV_ST_KILLING: + case TASKDEV_ST_GARBAGE: + /* on the kill process. wait until it becomes NOTASK. */ + up_write(&dev->state_sem); + mutex_unlock(&dev->usecount_mutex); + if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0) + return -EINTR; + devstate_write_unlock(dev); + goto restart; + } + + /* NOTASK */ + dev->state = 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_mutex); + /* out of control ??? */ + return -EINTR; } + dev->state = 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; + dev->state = TASKDEV_ST_NOTASK; + goto change_out; } - /* state_lock covers usecount, proc_list as well. */ +attached: + /* ATTACHED */ +#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN + if (dev->usecount > 0) { + up_write(&dev->state_sem); + return -EBUSY; + } +#endif dev->usecount++; - proc_list_add(&dev->proc_list, current); + proc_list_add(&dev->proc_list_lock, &dev->proc_list, current, file); file->f_op = &dev->fops; - devstate_unlock(dev); + up_write(&dev->state_sem); + mutex_unlock(&dev->usecount_mutex); +#ifdef DSP_PTE_FREE /* not used currently. */ + dsp_map_update(current); + dsp_cur_users_add(current); +#endif /* DSP_PTE_FREE */ return 0; -unlock_out: - devstate_unlock(dev); +change_out: + wake_up_interruptible_all(&dev->state_wait_q); + up_write(&dev->state_sem); + mutex_unlock(&dev->usecount_mutex); return ret; } @@ -1588,39 +1553,48 @@ static int dsp_task_release(struct inode *inode, struct file *file) unsigned int minor = MINOR(inode->i_rdev); struct taskdev *dev = taskdev[minor]; - /* state_lock covers usecount, proc_list as well. */ - spin_lock(&dev->state_lock); +#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_mutex); + if (--dev->usecount > 0) { + /* other processes are using this device. no state change. */ + mutex_unlock(&dev->usecount_mutex); + return 0; + } + + /* usecount == 0 */ + down_write(&dev->state_sem); - /* state can be ATTACHED, KILLING or GARBAGE here. */ - switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) { + /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */ + switch (dev->state & TASKDEV_ST_STATE_MASK) { - case OMAP_DSP_DEVSTATE_KILLING: - dev->usecount--; + case TASKDEV_ST_KILLING: break; - case OMAP_DSP_DEVSTATE_GARBAGE: - if(--dev->usecount == 0) { - dev->state = OMAP_DSP_DEVSTATE_NOTASK; - wake_up_interruptible_all(&dev->state_wait_q); - } + case TASKDEV_ST_GARBAGE: + dev->state = TASKDEV_ST_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); break; - case OMAP_DSP_DEVSTATE_ATTACHED: - if (dev->lock_pid == current->pid) - taskdev_unlock(dev); - proc_list_del(&dev->proc_list, current); - if (--dev->usecount == 0) { - if (minor >= n_task) { /* dynamic task */ - dev->state = OMAP_DSP_DEVSTATE_DELREQ; - /* wake up twch daemon for tdel */ - dsp_twch_touch(); - } + case TASKDEV_ST_ATTACHED: + case TASKDEV_ST_FREEZED: + if (is_dynamic_task(minor)) { + dev->state = TASKDEV_ST_DELREQ; + /* wake up twch daemon for tdel */ + dsp_twch_touch(); } break; } - spin_unlock(&dev->state_lock); + up_write(&dev->state_sem); + mutex_unlock(&dev->usecount_mutex); return 0; } @@ -1632,102 +1606,166 @@ int dsp_mkdev(char *name) struct taskdev *dev; int status; unsigned char minor; + int ret; - if (!dsp_is_ready()) { + 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"); - return -EBUSY; + ret = -EBUSY; + goto out; do_make: - if ((dev = kmalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(dev, 0, sizeof(struct taskdev)); + if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + goto out; + } if ((status = taskdev_init(dev, name, minor)) < 0) { kfree(dev); - return status; + ret = status; + goto out; } - return minor; + ret = minor; + +out: + mutex_unlock(&devmgr_lock); + return ret; } int dsp_rmdev(char *name) { unsigned char minor; + int status; int ret; - if (!dsp_is_ready()) { + 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)) { - if ((ret = dsp_rmdev_minor(minor)) < 0) - return ret; - return minor; + 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]; - spin_lock(&dev->state_lock); + 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.. + */ + dev->state = 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 & OMAP_DSP_DEVSTATE_STATE_MASK) { + switch (dev->state & TASKDEV_ST_STATE_MASK) { - case OMAP_DSP_DEVSTATE_NOTASK: + case TASKDEV_ST_NOTASK: /* fine */ - break; + goto notask; - case OMAP_DSP_DEVSTATE_ATTACHED: + case TASKDEV_ST_ATTACHED: + case TASKDEV_ST_FREEZED: /* task is working. kill it. */ - dev->state = OMAP_DSP_DEVSTATE_KILLING; - proclist_send_sigbus(&dev->proc_list); - spin_unlock(&dev->state_lock); - dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL); + dev->state = TASKDEV_ST_KILLING; + up_write(&dev->state_sem); + dsp_tdel_bh(dev, TDEL_KILL); goto invalidate; - case OMAP_DSP_DEVSTATE_ADDREQ: + case TASKDEV_ST_ADDREQ: /* open() is waiting. drain it. */ - dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; + dev->state = TASKDEV_ST_ADDFAIL; wake_up_interruptible_all(&dev->state_wait_q); break; - case OMAP_DSP_DEVSTATE_DELREQ: + case TASKDEV_ST_DELREQ: /* nobody is waiting. */ - dev->state = OMAP_DSP_DEVSTATE_NOTASK; + dev->state = TASKDEV_ST_NOTASK; wake_up_interruptible_all(&dev->state_wait_q); break; - case OMAP_DSP_DEVSTATE_ADDING: - case OMAP_DSP_DEVSTATE_DELING: - case OMAP_DSP_DEVSTATE_KILLING: - case OMAP_DSP_DEVSTATE_GARBAGE: - case OMAP_DSP_DEVSTATE_ADDFAIL: + 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; } - spin_unlock(&dev->state_lock); + up_write(&dev->state_sem); invalidate: /* wait for some time and hope the state is settled */ - devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ); - if (!(dev->state & OMAP_DSP_DEVSTATE_NOTASK)) { + 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); } - dev->state = OMAP_DSP_DEVSTATE_INVALID; - devstate_unlock(dev); +notask: + dev->state = TASKDEV_ST_INVALID; + devstate_read_unlock(dev); taskdev_delete(minor); kfree(dev); @@ -1749,25 +1787,26 @@ static void dsptask_dev_release(struct device *dev) static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor) { - struct class_device *cdev; - 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->ioctl_wait_q); + init_waitqueue_head(&dev->tctl_wait_q); mutex_init(&dev->read_mutex); mutex_init(&dev->write_mutex); - mutex_init(&dev->ioctl_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, OMAP_DSP_TNM_LEN); - dev->name[OMAP_DSP_TNM_LEN-1] = '\0'; - dev->state = (minor < n_task) ? OMAP_DSP_DEVSTATE_ATTACHED : - OMAP_DSP_DEVSTATE_NOTASK; + strncpy(dev->name, name, TNM_LEN); + dev->name[TNM_LEN-1] = '\0'; + dev->state = (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK; dev->usecount = 0; + mutex_init(&dev->usecount_mutex); memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations)); dev->dev.parent = &dsp_device.dev; @@ -1778,12 +1817,12 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor) device_create_file(&dev->dev, &dev_attr_devname); device_create_file(&dev->dev, &dev_attr_devstate); device_create_file(&dev->dev, &dev_attr_proc_list); - cdev = class_device_create(dsp_task_class, NULL, - MKDEV(OMAP_DSP_TASK_MAJOR, minor), - NULL, "dsptask%d", minor); + class_device_create(dsp_task_class, NULL, + MKDEV(OMAP_DSP_TASK_MAJOR, minor), + NULL, "dsptask%d", minor); init_waitqueue_head(&dev->state_wait_q); - spin_lock_init(&dev->state_lock); + init_rwsem(&dev->state_sem); return 0; } @@ -1799,16 +1838,14 @@ static void taskdev_delete(unsigned char minor) device_remove_file(&dev->dev, &dev_attr_proc_list); class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor)); device_unregister(&dev->dev); - proc_list_flush(&dev->proc_list); + proc_list_flush(&dev->proc_list_lock, &dev->proc_list); taskdev[minor] = NULL; } -static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) +static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task) { - unsigned short ttyp = task->ttyp; + u16 ttyp = task->ttyp; - dev->task = task; - task->dev = dev; dev->fops.read = sndtyp_acv(ttyp) ? sndtyp_wd(ttyp) ? dsp_task_read_wd_acv: @@ -1816,9 +1853,31 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) /* 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; + + fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */ + 32; /* active */ + if (init_fifo(&dev->rcvdt.fifo, fifosz) < 0) { + 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; @@ -1832,11 +1891,16 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) device_create_file(&dev->dev, &dev_attr_wsz); if (task->map_length) device_create_file(&dev->dev, &dev_attr_mmap); + + dev->task = task; + task->dev = dev; + + return 0; } static void taskdev_detach_task(struct taskdev *dev) { - unsigned short ttyp = dev->task->ttyp; + u16 ttyp = dev->task->ttyp; device_remove_file(&dev->dev, &dev_attr_taskname); device_remove_file(&dev->dev, &dev_attr_ttyp); @@ -1849,52 +1913,46 @@ static void taskdev_detach_task(struct taskdev *dev) if (dev->task->map_length) device_remove_file(&dev->dev, &dev_attr_mmap); - if (dev->task) { - dev->task = NULL; - dev->fops.read = NULL; - dev->fops.write = NULL; - printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name); - } + dev->fops.read = NULL; + taskdev_flush_buf(dev); + if (sndtyp_wd(ttyp)) + free_fifo(&dev->rcvdt.fifo); + + dev->fops.write = NULL; + dev->wsz = 0; + + printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name); + dev->task = NULL; } /* * tadd / tdel / tkill */ -int dsp_tadd(unsigned char minor, unsigned long adr) +static int dsp_tadd(struct taskdev *dev, dsp_long_t adr) { - struct taskdev *dev; struct dsptask *task; - struct mbcmd mb; struct mb_exarg arg; - unsigned char tid, tid_response; - unsigned short argv[2]; - int ret = minor; - - if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { - printk(KERN_ERR - "omapdsp: no task device with minor %d\n", minor); - return -EINVAL; - } + u8 tid, tid_response; + u16 argv[2]; + int ret = 0; - spin_lock(&dev->state_lock); - if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) { + 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)); - spin_unlock(&dev->state_lock); return -EINVAL; } - dev->state = OMAP_DSP_DEVSTATE_ADDING; - spin_unlock(&dev->state_lock); + dev->state = TASKDEV_ST_ADDING; + devstate_write_unlock(dev); - if (adr == OMAP_DSP_TADD_ABORTADR) { + if (adr == TADD_ABORTADR) { /* aborting tadd intentionally */ printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n"); goto fail_out; } if (adr >= DSPSPACE_SIZE) { printk(KERN_ERR - "omapdsp: illegal address 0x%08lx for tadd\n", adr); + "omapdsp: illegal address 0x%08x for tadd\n", adr); ret = -EINVAL; goto fail_out; } @@ -1904,13 +1962,12 @@ int dsp_tadd(unsigned char minor, unsigned long adr) argv[1] = adr & 0xffff; /* addrl */ if (mutex_lock_interruptible(&cfg_lock)) { - ret = -ERESTARTSYS; + ret = -EINTR; goto fail_out; } - cfg_tid = OMAP_DSP_TID_ANON; - cfg_cmd = MBCMD(TADD); - mbcmd_set(mb, MBCMD(TADD), 0, 0); - arg.tid = OMAP_DSP_TID_ANON; + cfg_tid = TID_ANON; + cfg_cmd = MBX_CMD_DSP_TADD; + arg.tid = TID_ANON; arg.argc = 2; arg.argv = argv; @@ -1926,7 +1983,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) cfg_cmd = 0; mutex_unlock(&cfg_lock); - if (tid == OMAP_DSP_TID_ANON) { + if (tid == TID_ANON) { printk(KERN_ERR "omapdsp: tadd failed!\n"); ret = -EINVAL; goto fail_out; @@ -1936,15 +1993,13 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ret = -EINVAL; goto fail_out; } - if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) { + if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto del_out; } - memset(task, 0, sizeof(struct dsptask)); if ((ret = dsp_task_config(task, tid)) < 0) goto free_out; - taskdev_attach_task(dev, task); if (strcmp(dev->name, task->name)) { printk(KERN_ERR @@ -1954,11 +2009,14 @@ int dsp_tadd(unsigned char minor, unsigned long adr) goto free_out; } + if ((ret = taskdev_attach_task(dev, task)) < 0) + goto free_out; + dsp_task_init(task); printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name); - dev->state = OMAP_DSP_DEVSTATE_ATTACHED; + dev->state = TASKDEV_ST_ATTACHED; wake_up_interruptible_all(&dev->state_wait_q); - return minor; + return 0; free_out: kfree(task); @@ -1966,19 +2024,18 @@ free_out: del_out: printk(KERN_ERR "omapdsp: deleting the task...\n"); - dev->state = OMAP_DSP_DEVSTATE_DELING; + dev->state = 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 = OMAP_DSP_TID_ANON; - cfg_cmd = MBCMD(TDEL); - mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL); - dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q); + cfg_tid = TID_ANON; + cfg_cmd = MBX_CMD_DSP_TDEL; + mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q); tid_response = cfg_tid; - cfg_tid = OMAP_DSP_TID_ANON; + cfg_tid = TID_ANON; cfg_cmd = 0; mutex_unlock(&cfg_lock); @@ -1987,84 +2044,161 @@ del_out: "DSP side could be corrupted.\n"); fail_out: - dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; + dev->state = TASKDEV_ST_ADDFAIL; wake_up_interruptible_all(&dev->state_wait_q); return ret; } -int dsp_tdel(unsigned char minor) +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); - return -EINVAL; + ret = -EINVAL; + goto out; } - spin_lock(&dev->state_lock); - if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) { + 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)); - spin_unlock(&dev->state_lock); return -EINVAL; } - dev->state = OMAP_DSP_DEVSTATE_DELING; - spin_unlock(&dev->state_lock); + dev->state = TASKDEV_ST_DELING; + devstate_write_unlock(dev); - return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE); + return dsp_tdel_bh(dev, TDEL_SAFE); } -int dsp_tkill(unsigned char minor) +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); - return -EINVAL; + 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. */ + dev->state = 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(); } - spin_lock(&dev->state_lock); - if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) { + + if (!(dev->state & (TASKDEV_ST_ATTACHED | + TASKDEV_ST_FREEZED))) { printk(KERN_ERR "omapdsp: task has not been attached for taskdev %s\n", dev->name); - spin_unlock(&dev->state_lock); + 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; } - dev->state = OMAP_DSP_DEVSTATE_KILLING; - proclist_send_sigbus(&dev->proc_list); - spin_unlock(&dev->state_lock); + dev->state = TASKDEV_ST_KILLING; + devstate_write_unlock(dev); - return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL); + return dsp_tdel_bh(dev, TDEL_KILL); } -static int dsp_tdel_bh(unsigned char minor, unsigned short type) +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 taskdev *dev = taskdev[minor]; struct dsptask *task; - struct mbcmd mb; - unsigned char tid, tid_response; - int ret = minor; + u8 tid, tid_response; + int ret = 0; task = dev->task; tid = task->tid; if (mutex_lock_interruptible(&cfg_lock)) { - if (type == OMAP_DSP_MBCMD_TDEL_SAFE) { - dev->state = OMAP_DSP_DEVSTATE_DELREQ; - return -ERESTARTSYS; + if (type == TDEL_SAFE) { + dev->state = TASKDEV_ST_DELREQ; + return -EINTR; } else { - tid_response = OMAP_DSP_TID_ANON; - ret = -ERESTARTSYS; + tid_response = TID_ANON; + ret = -EINTR; goto detach_out; } } - cfg_tid = OMAP_DSP_TID_ANON; - cfg_cmd = MBCMD(TDEL); - mbcmd_set(mb, MBCMD(TDEL), tid, type); - dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q); + cfg_tid = TID_ANON; + cfg_cmd = MBX_CMD_DSP_TDEL; + mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q); tid_response = cfg_tid; - cfg_tid = OMAP_DSP_TID_ANON; + cfg_tid = TID_ANON; cfg_cmd = 0; mutex_unlock(&cfg_lock); @@ -2075,14 +2209,14 @@ detach_out: if (tid_response != tid) { printk(KERN_ERR "omapdsp: %s failed!\n", - (type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill"); + (type == TDEL_SAFE) ? "tdel" : "tkill"); ret = -EINVAL; } - spin_lock(&dev->state_lock); - dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE : - OMAP_DSP_DEVSTATE_NOTASK; + down_write(&dev->state_sem); + dev->state = (dev->usecount > 0) ? TASKDEV_ST_GARBAGE : + TASKDEV_ST_NOTASK; wake_up_interruptible_all(&dev->state_wait_q); - spin_unlock(&dev->state_lock); + up_write(&dev->state_sem); return ret; } @@ -2094,18 +2228,18 @@ long taskdev_state_stale(unsigned char minor) { if (taskdev[minor]) { long state = taskdev[minor]->state; - taskdev[minor]->state |= OMAP_DSP_DEVSTATE_STALE; + taskdev[minor]->state |= TASKDEV_ST_STALE; return state; } else - return OMAP_DSP_DEVSTATE_NOTASK; + return TASKDEV_ST_NOTASK; } /* - * functions called from mailbox1 interrupt routine + * functions called from mailbox interrupt routine */ -void mbx1_wdsnd(struct mbcmd *mb) +void mbx_wdsnd(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; if ((tid >= TASKDEV_MAX) || (task == NULL)) { @@ -2125,14 +2259,15 @@ void mbx1_wdsnd(struct mbcmd *mb) return; } - write_word_to_fifo(&task->rcvdt.fifo, mb->data); + write_word_to_fifo(&task->dev->rcvdt.fifo, mb->data); wake_up_interruptible(&task->dev->read_wait_q); } -void mbx1_wdreq(struct mbcmd *mb) +void mbx_wdreq(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; + struct taskdev *dev; if ((tid >= TASKDEV_MAX) || (task == NULL)) { printk(KERN_ERR "mbx: WDREQ with illegal tid! %d\n", tid); @@ -2145,23 +2280,26 @@ void mbx1_wdreq(struct mbcmd *mb) return; } - spin_lock(&task->wsz_lock); - task->wsz = 2; - spin_unlock(&task->wsz_lock); - wake_up_interruptible(&task->dev->write_wait_q); + dev = task->dev; + spin_lock(&dev->wsz_lock); + dev->wsz = 2; + spin_unlock(&dev->wsz_lock); + wake_up_interruptible(&dev->write_wait_q); } -void mbx1_bksnd(struct mbcmd *mb) +void mbx_bksnd(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; - unsigned short bid = mb->data; + u8 tid = mb->cmd_l; + u16 bid = mb->data; struct dsptask *task = dsptask[tid]; - unsigned short cnt; + struct ipbuf_head *ipb_h; + u16 cnt; if (bid >= ipbcfg.ln) { printk(KERN_ERR "mbx: 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 "mbx: BKSND with illegal tid! %d\n", tid); @@ -2177,15 +2315,15 @@ void mbx1_bksnd(struct mbcmd *mb) "mbx: BKSND from private sending task! (task%d)\n", tid); goto unuse_ipbuf_out; } - if (sync_with_dsp(&ipbuf[bid]->sd, tid, 10) < 0) { + if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) { printk(KERN_ERR "mbx: BKSND - IPBUF sync failed!\n"); return; } /* should be done in DSP, but just in case. */ - ipbuf[bid]->next = OMAP_DSP_BID_NULL; + ipb_h->p->next = BID_NULL; - cnt = ipbuf[bid]->c; + cnt = ipb_h->p->c; if (cnt > ipbcfg.lsz) { printk(KERN_ERR "mbx: BKSND cnt(%d) > ipbuf line size(%d)!\n", cnt, ipbcfg.lsz); @@ -2194,12 +2332,10 @@ void mbx1_bksnd(struct mbcmd *mb) if (cnt == 0) { /* 0-byte send from DSP */ - unuse_ipbuf_nowait(bid); + unuse_ipbuf_nowait(ipb_h); goto done; } - spin_lock(&task->rcvdt.bk.link.lock); - ipblink_add_tail(&task->rcvdt.bk.link, bid, ipbuf); - spin_unlock(&task->rcvdt.bk.link.lock); + ipblink_add_tail(&task->dev->rcvdt.bk.link, bid); /* we keep coming bid and return alternative line to DSP. */ balance_ipbuf(); @@ -2208,15 +2344,16 @@ done: return; unuse_ipbuf_out: - unuse_ipbuf_nowait(bid); + unuse_ipbuf_nowait(ipb_h); return; } -void mbx1_bkreq(struct mbcmd *mb) +void mbx_bkreq(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; - unsigned short cnt = mb->data; + 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 "mbx: BKREQ with illegal tid! %d\n", tid); @@ -2240,35 +2377,37 @@ void mbx1_bkreq(struct mbcmd *mb) return; } - spin_lock(&task->wsz_lock); - task->wsz = cnt*2; - spin_unlock(&task->wsz_lock); - wake_up_interruptible(&task->dev->write_wait_q); + 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 mbx1_bkyld(struct mbcmd *mb) +void mbx_bkyld(struct mbcmd *mb) { - unsigned short bid = mb->data; + u16 bid = mb->data; + struct ipbuf_head *ipb_h; if (bid >= ipbcfg.ln) { printk(KERN_ERR "mbx: BKYLD with illegal bid! %d\n", bid); return; } + ipb_h = bid_to_ipbuf(bid); /* should be done in DSP, but just in case. */ - ipbuf[bid]->next = OMAP_DSP_BID_NULL; + ipb_h->p->next = BID_NULL; /* we don't need to sync with DSP */ ipb_bsycnt_dec(&ipbcfg); - release_ipbuf(bid); + release_ipbuf(ipb_h); } -void mbx1_bksndp(struct mbcmd *mb) +void mbx_bksndp(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; - struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk; - struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + struct ipbuf_p *ipbp; if ((tid >= TASKDEV_MAX) || (task == NULL)) { printk(KERN_ERR "mbx: BKSNDP with illegal tid! %d\n", tid); @@ -2292,23 +2431,23 @@ void mbx1_bksndp(struct mbcmd *mb) * 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 "mbx: BKSNDP - IPBUF sync failed!\n"); return; } printk(KERN_DEBUG "mbx: ipbuf_pvt_r->a = 0x%08lx\n", MKLONG(ipbp->ah, ipbp->al)); - spin_lock(&rcvdt->link.lock); - ipblink_add_pvt(&rcvdt->link); - spin_unlock(&rcvdt->link.lock); + ipblink_add_pvt(&task->dev->rcvdt.bk.link); wake_up_interruptible(&task->dev->read_wait_q); } -void mbx1_bkreqp(struct mbcmd *mb) +void mbx_bkreqp(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; - struct ipbuf_p *ipbp = task->ipbuf_pvt_w; + struct taskdev *dev; + struct ipbuf_p *ipbp; if ((tid >= TASKDEV_MAX) || (task == NULL)) { printk(KERN_ERR "mbx: BKREQP with illegal tid! %d\n", tid); @@ -2330,21 +2469,23 @@ void mbx1_bkreqp(struct mbcmd *mb) return; } - if (sync_with_dsp(&ipbp->s, OMAP_DSP_TID_FREE, 10) < 0) { + ipbp = task->ipbuf_pvt_w; + if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) { printk(KERN_ERR "mbx: BKREQP - IPBUF sync failed!\n"); return; } printk(KERN_DEBUG "mbx: ipbuf_pvt_w->a = 0x%08lx\n", MKLONG(ipbp->ah, ipbp->al)); - spin_lock(&task->wsz_lock); - task->wsz = ipbp->c*2; - spin_unlock(&task->wsz_lock); - wake_up_interruptible(&task->dev->write_wait_q); + 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 mbx1_tctl(struct mbcmd *mb) +void mbx_tctl(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; if ((tid >= TASKDEV_MAX) || (task == NULL)) { @@ -2352,34 +2493,40 @@ void mbx1_tctl(struct mbcmd *mb) return; } - if (!waitqueue_active(&task->dev->ioctl_wait_q)) { + if (!waitqueue_active(&task->dev->tctl_wait_q)) { printk(KERN_WARNING "mbx: unexpected TCTL from DSP!\n"); return; } - task->tctl_stat = mb->data; - wake_up_interruptible(&task->dev->ioctl_wait_q); + task->dev->tctl_stat = mb->data; + wake_up_interruptible(&task->dev->tctl_wait_q); } -void mbx1_tcfg(struct mbcmd *mb) +void mbx_tcfg(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; struct dsptask *task = dsptask[tid]; - unsigned short *tnm; - volatile unsigned short *buf; + u16 *tnm; + volatile u16 *buf; int i; if ((tid >= TASKDEV_MAX) || (task == NULL)) { printk(KERN_ERR "mbx: TCFG with illegal tid! %d\n", tid); return; } - if ((task->state != TASK_STATE_CFGREQ) || (cfg_cmd != MBCMD(TCFG))) { + if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBX_CMD_DSP_TCFG)) { printk(KERN_WARNING "mbx: unexpected TCFG from DSP!\n"); return; } + if (dsp_mem_enable(ipbuf_sys_da) < 0) { + printk(KERN_ERR "mbx: 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 "mbx: TCFG - IPBUF sync failed!\n"); + dsp_mem_disable(ipbuf_sys_da); goto out; } @@ -2387,41 +2534,42 @@ void mbx1_tcfg(struct mbcmd *mb) * read configuration data on system IPBUF */ buf = ipbuf_sys_da->d; - task->ttyp = buf[0]; - task->rcvdt.bk.ipbuf_pvt_r = MKVIRT(buf[1], buf[2]); - task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]); - task->map_base = MKVIRT(buf[5], buf[6]); - task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */ - tnm = MKVIRT(buf[9], buf[10]); + 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, OMAP_DSP_TNM_LEN, "task name buffer") <0) { + if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) { task->name[0] = '\0'; goto out; } - for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) { + for (i = 0; i < TNM_LEN-1; i++) { /* avoiding byte access */ - unsigned short tmp = tnm[i]; + u16 tmp = tnm[i]; task->name[i] = tmp & 0x00ff; if (!tmp) break; } - task->name[OMAP_DSP_TNM_LEN-1] = '\0'; + task->name[TNM_LEN-1] = '\0'; - task->state = TASK_STATE_READY; + task->state = TASK_ST_READY; out: wake_up_interruptible(&cfg_wait_q); } -void mbx1_tadd(struct mbcmd *mb) +void mbx_tadd(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; - if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TADD))) { + if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBX_CMD_DSP_TADD)) { printk(KERN_WARNING "mbx: unexpected TADD from DSP!\n"); return; } @@ -2429,11 +2577,11 @@ void mbx1_tadd(struct mbcmd *mb) wake_up_interruptible(&cfg_wait_q); } -void mbx1_tdel(struct mbcmd *mb) +void mbx_tdel(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; - if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TDEL))) { + if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBX_CMD_DSP_TDEL)) { printk(KERN_WARNING "mbx: unexpected TDEL from DSP!\n"); return; } @@ -2441,25 +2589,28 @@ void mbx1_tdel(struct mbcmd *mb) wake_up_interruptible(&cfg_wait_q); } -void mbx1_err_fatal(unsigned char tid) +void mbx_err_fatal(u8 tid) { struct dsptask *task = dsptask[tid]; + struct taskdev *dev; if ((tid >= TASKDEV_MAX) || (task == NULL)) { printk(KERN_ERR "mbx: FATAL ERR with illegal tid! %d\n", tid); return; } - spin_lock(&task->dev->state_lock); - proclist_send_sigbus(&task->dev->proc_list); - spin_unlock(&task->dev->state_lock); + /* 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 short *dbg_buf; -static unsigned short dbg_buf_sz, dbg_line_sz; +static u16 *dbg_buf; +static u16 dbg_buf_sz, dbg_line_sz; static int dbg_rp; -int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz) +int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz) { #ifdef OLD_BINARY_SUPPORT if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) { @@ -2495,26 +2646,26 @@ void dsp_dbg_stop(void) } #ifdef OLD_BINARY_SUPPORT -static void mbx1_dbg_old(struct mbcmd *mb); +static void mbx_dbg_old(struct mbcmd *mb); #endif -void mbx1_dbg(struct mbcmd *mb) +void mbx_dbg(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; int cnt = mb->data; char s[80], *s_end = &s[79], *p; - unsigned short *src; + u16 *src; int i; #ifdef OLD_BINARY_SUPPORT if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) { - mbx1_dbg_old(mb); + mbx_dbg_old(mb); return; } #endif if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) && - (tid != OMAP_DSP_TID_ANON)) { + (tid != TID_ANON)) { printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid); return; } @@ -2530,7 +2681,7 @@ void mbx1_dbg(struct mbcmd *mb) src = &dbg_buf[dbg_rp]; p = s; for (i = 0; i < cnt; i++) { - unsigned short tmp; + u16 tmp; /* * Be carefull that dbg_buf should not be read with * 1-byte access since it might be placed in DARAM/SARAM @@ -2565,36 +2716,40 @@ void mbx1_dbg(struct mbcmd *mb) } #ifdef OLD_BINARY_SUPPORT -static void mbx1_dbg_old(struct mbcmd *mb) +static void mbx_dbg_old(struct mbcmd *mb) { - unsigned char tid = mb->cmd_l; + u8 tid = mb->cmd_l; char s[80], *s_end = &s[79], *p; - unsigned short *src; - volatile unsigned short *buf; + u16 *src; + volatile u16 *buf; int cnt; int i; if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) && - (tid != OMAP_DSP_TID_ANON)) { + (tid != TID_ANON)) { printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid); return; } + if (dsp_mem_enable(ipbuf_sys_da) < 0) { + printk(KERN_ERR "mbx: DBG - ipbuf_sys_da read failed!\n"); + return; + } if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) { printk(KERN_ERR "mbx: DBG - IPBUF sync failed!\n"); - return; + 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) - return; + goto out2; if (dsp_mem_enable(src) < 0) - return; + goto out2; p = s; for (i = 0; i < cnt; i++) { - unsigned short tmp; + u16 tmp; /* * Be carefull that ipbuf should not be read with * 1-byte access since it might be placed in DARAM/SARAM @@ -2623,28 +2778,33 @@ static void mbx1_dbg_old(struct mbcmd *mb) printk(KERN_INFO "%s\n", s); } - release_ipbuf_pvt(ipbuf_sys_da); dsp_mem_disable(src); +out2: + release_ipbuf_pvt(ipbuf_sys_da); +out1: + dsp_mem_disable(ipbuf_sys_da); } #endif /* OLD_BINARY_SUPPORT */ /* - * sysfs files + * sysfs files: for each device */ + +/* devname */ static ssize_t devname_show(struct device *d, struct device_attribute *attr, char *buf) { - struct taskdev *dev = to_taskdev(d); - return sprintf(buf, "%s\n", dev->name); + return sprintf(buf, "%s\n", to_taskdev(d)->name); } +/* devstate */ static ssize_t devstate_show(struct device *d, struct device_attribute *attr, char *buf) { - struct taskdev *dev = to_taskdev(d); - return sprintf(buf, "%s\n", devstate_name(dev->state)); + 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) { @@ -2653,32 +2813,47 @@ static ssize_t proc_list_show(struct device *d, struct device_attribute *attr, int len = 0; dev = to_taskdev(d); - spin_lock(&dev->state_lock); + spin_lock(&dev->proc_list_lock); list_for_each_entry(pl, &dev->proc_list, list_head) { - len += sprintf(buf + len, "%d\n", pl->pid); + /* need to lock tasklist_lock before calling + * find_task_by_pid_type. */ + if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) != NULL) + len += sprintf(buf + len, "%d\n", pl->pid); + read_unlock(&tasklist_lock); } - spin_unlock(&dev->state_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) { - unsigned short ttyp = to_taskdev(d)->task->ttyp; + 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" : @@ -2693,44 +2868,48 @@ static ssize_t ttyp_show(struct device *d, struct device_attribute *attr, (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 fifo_struct *fifo = &to_taskdev(d)->task->rcvdt.fifo; + struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo; return sprintf(buf, "%d\n", fifo->sz); } static int fifosz_store(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct dsptask *task = to_taskdev(d)->task; + struct taskdev *dev = to_taskdev(d); unsigned long fifosz; int ret; fifosz = simple_strtol(buf, NULL, 10); - ret = dsp_task_set_fifosz(task, fifosz); + ret = taskdev_set_fifosz(dev, fifosz); return (ret < 0) ? ret : strlen(buf); } +/* fifocnt */ static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr, char *buf) { - struct fifo_struct *fifo = &to_taskdev(d)->task->rcvdt.fifo; + struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo; return sprintf(buf, "%d\n", fifo->cnt); } -static __inline__ char *bid_name(unsigned short bid) +/* ipblink */ +static __inline__ char *bid_name(u16 bid) { static char s[6]; switch (bid) { - case OMAP_DSP_BID_NULL: + case BID_NULL: return "NULL"; - case OMAP_DSP_BID_PVT: + case BID_PVT: return "PRIVATE"; default: sprintf(s, "%d", bid); @@ -2741,7 +2920,7 @@ static __inline__ char *bid_name(unsigned short bid) static ssize_t ipblink_show(struct device *d, struct device_attribute *attr, char *buf) { - struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->task->rcvdt.bk; + struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk; int len; spin_lock(&rcvdt->link.lock); @@ -2752,12 +2931,14 @@ static ssize_t ipblink_show(struct device *d, struct device_attribute *attr, 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)->task->wsz); + return sprintf(buf, "%d\n", to_taskdev(d)->wsz); } +/* mmap */ static ssize_t mmap_show(struct device *d, struct device_attribute *attr, char *buf) { @@ -2766,25 +2947,27 @@ static ssize_t mmap_show(struct device *d, struct device_attribute *attr, } /* - * called from ipbuf_read_proc() + * called from ipbuf_show() */ -int ipbuf_is_held(unsigned char tid, unsigned short bid) +int ipbuf_is_held(u8 tid, u16 bid) { struct dsptask *task = dsptask[tid]; - unsigned short b; + struct ipblink *link; + u16 b; int ret = 0; if (task == NULL) return 0; - spin_lock(&task->rcvdt.bk.link.lock); - ipblink_for_each(b, &task->rcvdt.bk.link, ipbuf) { + link = &task->dev->rcvdt.bk.link; + spin_lock(&link->lock); + ipblink_for_each(b, link) { if (b == bid) { /* found */ ret = 1; break; } } - spin_unlock(&task->rcvdt.bk.link.lock); + spin_unlock(&link->lock); return ret; } diff --git a/arch/arm/plat-omap/dsp/taskwatch.c b/arch/arm/plat-omap/dsp/taskwatch.c index cdd71823c74..f2bccc9ea3d 100644 --- a/arch/arm/plat-omap/dsp/taskwatch.c +++ b/arch/arm/plat-omap/dsp/taskwatch.c @@ -1,41 +1,34 @@ /* - * linux/arch/arm/mach-omap/dsp/taskwatch.c + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * OMAP DSP task watch device driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 200%/05/16: DSP Gateway version 3.3 */ #include -#include -#include #include #include -#include #include -#include #include -#include -#include +#include "dsp_mbcmd.h" #include "dsp.h" +#include "ioctl.h" static DECLARE_WAIT_QUEUE_HEAD(read_wait_q); static unsigned int change_cnt; @@ -49,14 +42,14 @@ void dsp_twch_touch(void) /* * @count: represents the device counts of the user's interst */ -static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count, +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; - if (!dsp_is_ready()) { + if (dsp_cfgstat_get_stat() != CFGSTAT_READY) { printk(KERN_ERR "omapdsp: dsp has not been configured.\n"); return -EINVAL; } @@ -74,7 +67,7 @@ static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count, remove_wait_queue(&read_wait_q, &wait); /* unconfigured while waiting ;-( */ - if (dsp_is_ready()) + if (dsp_cfgstat_get_stat() != CFGSTAT_READY) return -EINVAL; } @@ -112,62 +105,50 @@ static unsigned int dsp_twch_poll(struct file *file, poll_table *wait) static int dsp_twch_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - static DEFINE_MUTEX(ioctl_lock); int ret; - if (mutex_lock_interruptible(&ioctl_lock)) - return -ERESTARTSYS; - switch (cmd) { - case OMAP_DSP_TWCH_IOCTL_MKDEV: + case TWCH_IOCTL_MKDEV: { - char name[OMAP_DSP_TNM_LEN]; - if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) { - ret = -EFAULT; - goto up_out; - } - name[OMAP_DSP_TNM_LEN-1] = '\0'; + 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 OMAP_DSP_TWCH_IOCTL_RMDEV: + case TWCH_IOCTL_RMDEV: { - char name[OMAP_DSP_TNM_LEN]; - if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) { - ret = -EFAULT; - goto up_out; - } - name[OMAP_DSP_TNM_LEN-1] = '\0'; + 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 OMAP_DSP_TWCH_IOCTL_TADD: + case TWCH_IOCTL_TADD: { struct omap_dsp_taddinfo ti; - if (copy_from_user(&ti, (void *)arg, sizeof(ti))) { - ret = -EFAULT; - goto up_out; - } - ret = dsp_tadd(ti.minor, ti.taskadr); + if (copy_from_user(&ti, (void __user *)arg, sizeof(ti))) + return -EFAULT; + ret = dsp_tadd_minor(ti.minor, ti.taskadr); break; } - case OMAP_DSP_TWCH_IOCTL_TDEL: - ret = dsp_tdel(arg); + case TWCH_IOCTL_TDEL: + ret = dsp_tdel_minor(arg); break; - case OMAP_DSP_TWCH_IOCTL_TKILL: - ret = dsp_tkill(arg); + case TWCH_IOCTL_TKILL: + ret = dsp_tkill_minor(arg); break; default: - ret = -ENOIOCTLCMD; + return -ENOIOCTLCMD; } -up_out: - mutex_unlock(&ioctl_lock); return ret; } diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.S b/arch/arm/plat-omap/dsp/uaccess_dsp.S index 6e427a2b2d4..6ffd68b2c42 100644 --- a/arch/arm/plat-omap/dsp/uaccess_dsp.S +++ b/arch/arm/plat-omap/dsp/uaccess_dsp.S @@ -1,27 +1,24 @@ /* - * linux/arch/arm/mach-omap/dsp/uaccess_dsp.S + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * user memory access functions for DSP driver + * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2004,2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2004/06/29: DSP Gateway version 3.3 */ #include diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.h b/arch/arm/plat-omap/dsp/uaccess_dsp.h index d1eb7e52e27..686faf2e9b7 100644 --- a/arch/arm/plat-omap/dsp/uaccess_dsp.h +++ b/arch/arm/plat-omap/dsp/uaccess_dsp.h @@ -1,34 +1,31 @@ /* - * linux/arch/arm/mach-omap/dsp/uaccess_dsp.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Header for user access functions for DSP driver + * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2002-2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Modified from linux/include/asm-arm/uaccess.h - * by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2004/06/29: DSP Gateway version 3.3 */ #ifndef _OMAP_DSP_UACCESS_DSP_H #define _OMAP_DSP_UACCESS_DSP_H #include +#include "dsp_common.h" #define HAVE_ASM_COPY_FROM_USER_DSP_2B @@ -39,12 +36,6 @@ extern unsigned long __copy_to_user_dsp_2b(void __user *to, const void *from); #endif -extern unsigned long dspmem_base, dspmem_size; -#define is_dsp_internal_mem(va) \ - (((unsigned long)(va) >= dspmem_base) && \ - ((unsigned long)(va) < dspmem_base + dspmem_size)) - - #ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B static __inline__ unsigned long copy_from_user_dsp_2b(void *to, const void *from) @@ -181,6 +172,4 @@ static __inline__ unsigned long copy_to_user_dsp(void *to, const void *from, return n; } -#undef is_dsp_internal_mem - #endif /* _OMAP_DSP_UACCESS_DSP_H */ diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c new file mode 100644 index 00000000000..6a37582141e --- /dev/null +++ b/arch/arm/plat-omap/mailbox.c @@ -0,0 +1,574 @@ +/* + * OMAP mailbox driver + * + * Copyright (C) 2006 Nokia Corporation. All rights reserved. + * + * Contact: Toshihiro Kobayashi + * + * 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 +#include +#include +#include +#include +#ifdef CONFIG_ARCH_OMAP2 +#include +#endif +#include +#ifdef CONFIG_ARCH_OMAP1 +#include +#endif +#include +#include "mailbox_hw.h" + +#if defined(CONFIG_ARCH_OMAP1) + +#define read_mbx(m, msgp) \ + do { \ + *(msgp) = omap_readw((m)->data_r); \ + *(msgp) |= ((mbx_msg_t)omap_readw((m)->cmd_r)) << 16; \ + } while (0) +#define write_mbx(m, msg) \ + do { \ + omap_writew((msg) & 0xffff, (m)->data_w); \ + omap_writew((msg) >> 16, (m)->cmd_w); \ + } while (0) +#define enable_newmsg_irq(m) enable_irq((m)->irq) +#define disable_newmsg_irq(m) disable_irq((m)->irq) +#define mbx_is_notfull(m) (omap_readw((m)->flag_w) == 0) + +#elif defined(CONFIG_ARCH_OMAP2) + +#define omap_bit_setl(b,r) \ + do { omap_writel(omap_readl(r) | (b), (r)); } while(0) +#define omap_bit_clrl(b,r) \ + do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0) + +#define read_mbx(m, msgp) \ + do { *(msgp) = omap_readl((m)->message_r); } while (0) +#define write_mbx(m, msg) omap_writel(msg, (m)->message_w) +#define enable_newmsg_irq(m) omap_bit_setl((m)->newmsg_bit, (m)->irqenable) +#define disable_newmsg_irq(m) omap_bit_clrl((m)->newmsg_bit, (m)->irqenable) +#define enable_notfull_irq(m) omap_bit_setl((m)->notfull_bit, (m)->irqenable) +#define disable_notfull_irq(m) omap_bit_clrl((m)->notfull_bit, (m)->irqenable) +#define clear_newmsg_irq(m) omap_writel((m)->newmsg_bit, (m)->irqstatus) +#define clear_notfull_irq(m) omap_writel((m)->notfull_bit, (m)->irqstatus) +#define notfull_irq_enabled(m) (omap_readl((m)->irqenable) & (m)->notfull_bit) +#define has_newmsg_irq(m) (omap_readl((m)->irqstatus) & (m)->newmsg_bit) +#define has_notfull_irq(m) (omap_readl((m)->irqstatus) & (m)->notfull_bit) +#define mbx_nomsg(m) (omap_readl((m)->msgstatus_r) == 0) +#define mbx_is_notfull(m) (omap_readl((m)->fifostatus_w) == 0) + +#endif /* CONFIG_ARCH_OMAP2 */ + +static void do_mbx(void *p); + +#define MBQ_DEPTH 16 +struct mbq { + mbx_msg_t msg[MBQ_DEPTH]; + int rp, wp, full; +}; + +#define mbq_inc(p) do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0) + +#if defined(CONFIG_ARCH_OMAP1) +# define MBX_USE_SEQ_BIT /* XXX */ +#elif defined(CONFIG_ARCH_OMAP2) +# undef MBX_USE_SEQ_BIT +#endif + +struct mbx { + char *name; + unsigned int irq; + char irq_devid_newmsg; +#ifdef CONFIG_ARCH_OMAP2 + char irq_devid_notfull; +#endif +#ifdef MBX_USE_SEQ_BIT + mbx_msg_t seq_snd; + mbx_msg_t seq_rcv; + /* seq_rcv should be initialized with any value other than + * 0 and 1 << 31, to allow either value for the first + * message. */ +#endif + mbx_receiver_t *receiver_map[MBX_CMD_MAX]; + struct work_struct work; + struct mbq mbq; +#ifdef CONFIG_ARCH_OMAP2 + wait_queue_head_t full_wait_q; +#endif + +#if defined(CONFIG_ARCH_OMAP1) + void *cmd_w; + void *data_w; + void *flag_w; + void *cmd_r; + void *data_r; +#elif defined(CONFIG_ARCH_OMAP2) + void *irqenable; + void *irqstatus; + void *message_w; + void *message_r; + void *fifostatus_w; + void *msgstatus_r; + u32 notfull_bit; + u32 newmsg_bit; +#endif +}; + +#if defined(CONFIG_ARCH_OMAP1) + +#if defined(CONFIG_ARCH_OMAP15XX) +#define INT_DSP_MAILBOX1 INT_1510_DSP_MAILBOX1 +#elif defined(CONFIG_ARCH_OMAP16XX) +#define INT_DSP_MAILBOX1 INT_1610_DSP_MAILBOX1 +#endif + +static struct mbx mbx_dsp = { + .name = "DSP", + .irq = INT_DSP_MAILBOX1, + .work = __WORK_INITIALIZER(mbx_dsp.work, do_mbx, &mbx_dsp), + + .cmd_w = (void *)MAILBOX_ARM2DSP1b, + .data_w = (void *)MAILBOX_ARM2DSP1, + .flag_w = (void *)MAILBOX_ARM2DSP1_Flag, + .cmd_r = (void *)MAILBOX_DSP2ARM1b, + .data_r = (void *)MAILBOX_DSP2ARM1, +}; + +#elif defined(CONFIG_ARCH_OMAP2) + +/* + * MAILBOX 0: ARM -> DSP, + * MAILBOX 1: ARM <- DSP. + * MAILBOX 2: ARM -> IVA, + * MAILBOX 3: ARM <- IVA. + */ +static struct mbx mbx_dsp = { + .name = "DSP", + .irq = INT_24XX_MAIL_U0_MPU, + .work = __WORK_INITIALIZER(mbx_dsp.work, do_mbx, &mbx_dsp), + .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbx_dsp.full_wait_q), + + .irqenable = (void *)MAILBOX_IRQENABLE_0, + .irqstatus = (void *)MAILBOX_IRQSTATUS_0, + .message_w = (void *)MAILBOX_MESSAGE_0, + .message_r = (void *)MAILBOX_MESSAGE_1, + .fifostatus_w = (void *)MAILBOX_FIFOSTATUS_0, + .msgstatus_r = (void *)MAILBOX_MSGSTATUS_1, + .notfull_bit = MAILBOX_IRQ_NOTFULL(0), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), +}; +static struct mbx mbx_iva = { + .name = "IVA", + .irq = INT_24XX_MAIL_U3_MPU, + .work = __WORK_INITIALIZER(mbx_iva.work, do_mbx, &mbx_iva), + .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbx_iva.full_wait_q), + + .irqenable = (void *)MAILBOX_IRQENABLE_3, + .irqstatus = (void *)MAILBOX_IRQSTATUS_3, + .message_w = (void *)MAILBOX_MESSAGE_2, + .message_r = (void *)MAILBOX_MESSAGE_3, + .fifostatus_w = (void *)MAILBOX_FIFOSTATUS_2, + .msgstatus_r = (void *)MAILBOX_MSGSTATUS_3, + .notfull_bit = MAILBOX_IRQ_NOTFULL(2), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(3), +}; + +#endif /* CONFIG_ARCH_OMAP2 */ + +static struct mbx *mbxes[] = { + &mbx_dsp, +#ifdef CONFIG_ARCH_OMAP2 + &mbx_iva, +#endif +}; + +struct mbx *mbx_get(const char *id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mbxes); i++) { + if (!strcmp(id, mbxes[i]->name)) + return mbxes[i]; + } + + return ERR_PTR(-ENOENT); +} + +#if defined(CONFIG_ARCH_OMAP1) +static __inline__ int mbsync_irq_save(struct mbx *mbx, unsigned long *flags, + int try_cnt) +{ + int cnt; + + local_irq_save(*flags); + if (mbx_is_notfull(mbx)) + return 0; + /* + * mailbox is busy. wait for some usecs... + */ + local_irq_restore(*flags); + for (cnt = 0; cnt < try_cnt; cnt++) { + udelay(1); + local_irq_save(*flags); + if (mbx_is_notfull(mbx)) /* success! */ + return 0; + local_irq_restore(*flags); + } + + /* fail! */ + return -1; +} +#elif defined(CONFIG_ARCH_OMAP2) +static __inline__ int mbsync_irq_save(struct mbx *mbx, unsigned long *flags) +{ + long current_state; + DECLARE_WAITQUEUE(wait, current); + + do { + local_irq_save(*flags); + if (mbx_is_notfull(mbx)) + return 0; + + /* + * mailbox is busy. + */ + local_irq_restore(*flags); + enable_notfull_irq(mbx); + + /* wait until the FIFO becomes not-full */ + add_wait_queue(&mbx->full_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (!mbx_is_notfull(mbx)) /* last check */ + schedule(); + set_current_state(current_state); + remove_wait_queue(&mbx->full_wait_q, &wait); + + if (signal_pending(current)) + return -1; + } while (1); +} +#endif + +/* + * message dispatcher API + */ +int mbx_send(struct mbx *mbx, mbx_msg_t msg) +{ + unsigned long flags; + +#if defined(CONFIG_ARCH_OMAP1) + /* + * DSP mailbox interrupt latency must be less than 1ms. + */ + if (mbsync_irq_save(mbx, &flags, 1000) < 0) { + printk(KERN_ERR + "mailbox(%s) is busy. message 0x%08x is aborting.\n", + mbx->name, msg); + return -1; + } +#elif defined(CONFIG_ARCH_OMAP2) + if (mbsync_irq_save(mbx, &flags) < 0) + return -1; +#endif + +#ifdef MBX_USE_SEQ_BIT + /* add seq_snd to msg */ + msg = (msg & 0x7fffffff) | mbx->seq_snd; + /* flip seq_snd */ + mbx->seq_snd ^= 1 << 31; +#endif + + write_mbx(mbx, msg); + + local_irq_restore(flags); + return 0; +} + +/* + * register / unregister API + */ +int register_mbx_receiver(struct mbx *mbx, unsigned char cmd, + mbx_receiver_t *rcv) +{ + if (cmd >= MBX_CMD_MAX) { + printk(KERN_ERR "register_mbx_receiver(): " + "bad cmd (0x%x)\n", cmd); + return -EINVAL; + } + if (mbx->receiver_map[cmd] != NULL) { + printk(KERN_ERR "register_mbx_receiver(): cmd 0x%x is " + "already reserved.\n", cmd); + return -EINVAL; + } + + mbx->receiver_map[cmd] = rcv; + return 0; +} + +int unregister_mbx_receiver(struct mbx *mbx, unsigned char cmd, + mbx_receiver_t *rcv) +{ + if (cmd >= MBX_CMD_MAX) { + printk(KERN_ERR "unregister_mbx_receiver(): " + "bad cmd (0x%x)\n", cmd); + return -EINVAL; + } + if (mbx->receiver_map[cmd] != rcv) { + printk(KERN_ERR "unregister_mbx_receiver(): cmd 0x%x and " + "receiver function mismatch!\n", cmd); + return -EINVAL; + } + + mbx->receiver_map[cmd] = NULL; + return 0; +} + +/* + * IRQ disable / enable API + */ +void disable_mbx_irq(struct mbx *mbx) +{ + disable_irq(mbx->irq); +} + +void enable_mbx_irq(struct mbx *mbx) +{ + enable_irq(mbx->irq); +} + +/* + * init_seq API + */ +void mbx_init_seq(struct mbx *mbx) +{ +#ifdef MBX_USE_SEQ_BIT + /* backward compatibility */ + mbx->seq_snd = 0x80000000; + + /* any value other than 0 and 1 << 31 */ + mbx->seq_rcv = 0xffffffff; +#endif /* MBX_USE_SEQ_BIT */ +} + +/* + * receiver workqueue + */ +static void do_mbx(void *p) +{ + int empty = 0; + struct mbx *mbx = (struct mbx *)p; + struct mbq *mbq = &mbx->mbq; + mbx_receiver_t *receiver; + mbx_msg_t msg; +#ifdef MBX_USE_SEQ_BIT + mbx_msg_t seq; +#endif + + disable_newmsg_irq(mbx); + if ((mbq->rp == mbq->wp) && !mbq->full) + empty = 1; + enable_newmsg_irq(mbx); + + while (!empty) { + msg = mbq->msg[mbq->rp]; +#ifdef MBX_USE_SEQ_BIT + seq = msg & (1 << 31); + + if (seq == mbx->seq_rcv) { + printk(KERN_ERR + "mbx: illegal seq bit! ignoring this command. " + "(%08x)\n", msg); + goto inc; + } + mbx->seq_rcv = seq; +#endif + + /* call receiver function */ + if ((receiver = mbx->receiver_map[(msg >> 24) & 0x7f]) == NULL) + printk(KERN_ERR + "mbx: unknown message (%08x) received from " + "%s.\n", msg, mbx->name); + else + receiver(msg); + +#ifdef MBX_USE_SEQ_BIT +inc: +#endif + disable_newmsg_irq(mbx); + mbq_inc(mbq->rp); + if (mbq->rp == mbq->wp) + empty = 1; + /* if mbq has been full, now we have a room. */ + if (mbq->full) { + mbq->full = 0; + enable_newmsg_irq(mbx); + } + enable_newmsg_irq(mbx); + } +} + +/* + * interrupt handler + */ +static irqreturn_t mbx_int_newmsg(int irq, void *p, struct pt_regs *regs) +{ + struct mbx *mbx = container_of(p, struct mbx, irq_devid_newmsg); + struct mbq *mbq = &mbx->mbq; + mbx_msg_t *msg; + +#ifdef CONFIG_ARCH_OMAP2 + /* + * mailbox IRQ can be muxed. + * if it is not a newmsg interrupt, do nothing. + */ + if (!has_newmsg_irq(mbx)) + return IRQ_NONE; +#endif + + do { +#ifdef CONFIG_ARCH_OMAP2 + if (mbx_nomsg(mbx)) { + /* no more messages in the fifo. clear IRQ source. */ + clear_newmsg_irq(mbx); + break; + } +#endif + + msg = &mbq->msg[mbq->wp]; + read_mbx(mbx, msg); + + mbq_inc(mbq->wp); + if (mbq->wp == mbq->rp) { /* mbq is full */ + mbq->full = 1; + disable_newmsg_irq(mbx); + break; + } +#if defined(CONFIG_ARCH_OMAP1) + } while (0); /* do it once */ +#elif defined(CONFIG_ARCH_OMAP2) + } while (1); +#endif + + schedule_work(&mbx->work); + return IRQ_HANDLED; +} + +#ifdef CONFIG_ARCH_OMAP2 +static irqreturn_t mbx_int_notfull(int irq, void *p, struct pt_regs *regs) +{ + struct mbx *mbx = container_of(p, struct mbx, irq_devid_notfull); + + /* + * mailbox IRQ can be muxed. + * if it is not a notfull interrupt, we do nothing. + */ +#if 0 + if (!has_notfull_irq(mbx)) +#else + if (!(has_notfull_irq(mbx) && notfull_irq_enabled(mbx))) +#endif + return IRQ_NONE; + + disable_notfull_irq(mbx); + +#if 0 /* + * note: this doesn't seeem to work as explained in the manual. + * IRQSTATUS:NOTFULL can't be cleared even we write 1 to that bit. + * It is always set when it's not full, regardless of IRQENABLE setting. + */ + clear_notfull_irq(mbx); +#endif + + wake_up_interruptible_all(&mbx->full_wait_q); + return IRQ_HANDLED; +} +#endif /* CONFIG_ARCH_OMAP2 */ + +static int __init mbx_request_irq(struct mbx *mbx, const char *devname) +{ + int ret; + +#ifdef CONFIG_ARCH_OMAP2 + enable_newmsg_irq(mbx); +#endif + + ret = request_irq(mbx->irq, mbx_int_newmsg, SA_INTERRUPT | SA_SHIRQ, + devname, &mbx->irq_devid_newmsg); + if (ret) { + printk(KERN_ERR + "failed to register DSP mailbox newmsg interrupt: " + "%d\n", ret); + return ret; + } + +#ifdef CONFIG_ARCH_OMAP2 + ret = request_irq(mbx->irq, mbx_int_notfull, SA_INTERRUPT | SA_SHIRQ, + devname, &mbx->irq_devid_notfull); + if (ret) { + printk(KERN_ERR + "failed to register DSP mailbox notfull interrupt: " + "%d\n", ret); + return ret; + } +#endif + + return 0; +} + +static int __init omap_mailbox_init(void) +{ + int ret; +#ifdef CONFIG_ARCH_OMAP2 + struct clk *mbx_ick_handle; +#endif + + printk(KERN_INFO "Initializing OMAP Mailboxes\n"); +#ifdef CONFIG_ARCH_OMAP2 + /* + * FIXME: mbx_ick will never unsed + */ + mbx_ick_handle = clk_get(NULL, "mailboxes_ick"); + if (IS_ERR(mbx_ick_handle)) { + printk("Could not get mailboxes_ick\n"); + return -ENODEV; + } else + clk_enable(mbx_ick_handle); +#endif + + if ((ret = mbx_request_irq(&mbx_dsp, "mbx_dsp")) != 0) + return ret; +#ifdef CONFIG_ARCH_OMAP2 + if ((ret = mbx_request_irq(&mbx_iva, "mbx_iva")) != 0) + return ret; +#endif + + return 0; +} + +arch_initcall(omap_mailbox_init); + +EXPORT_SYMBOL(mbx_get); +EXPORT_SYMBOL(mbx_send); +EXPORT_SYMBOL(register_mbx_receiver); +EXPORT_SYMBOL(unregister_mbx_receiver); +EXPORT_SYMBOL(disable_mbx_irq); +EXPORT_SYMBOL(enable_mbx_irq); +EXPORT_SYMBOL(mbx_init_seq); diff --git a/arch/arm/plat-omap/mailbox_hw.h b/arch/arm/plat-omap/mailbox_hw.h new file mode 100644 index 00000000000..9b10433dbd0 --- /dev/null +++ b/arch/arm/plat-omap/mailbox_hw.h @@ -0,0 +1,79 @@ +/* + * Header for OMAP mailbox driver + * + * Copyright (C) 2006 Nokia Corporation. All rights reserved. + * + * Contact: Toshihiro Kobayashi + * + * 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 + +#if defined(CONFIG_ARCH_OMAP1) + +#define MAILBOX_BASE (0xfffcf000) +#define MAILBOX_ARM2DSP1 (MAILBOX_BASE + 0x00) +#define MAILBOX_ARM2DSP1b (MAILBOX_BASE + 0x04) +#define MAILBOX_DSP2ARM1 (MAILBOX_BASE + 0x08) +#define MAILBOX_DSP2ARM1b (MAILBOX_BASE + 0x0c) +#define MAILBOX_DSP2ARM2 (MAILBOX_BASE + 0x10) +#define MAILBOX_DSP2ARM2b (MAILBOX_BASE + 0x14) +#define MAILBOX_ARM2DSP1_Flag (MAILBOX_BASE + 0x18) +#define MAILBOX_DSP2ARM1_Flag (MAILBOX_BASE + 0x1c) +#define MAILBOX_DSP2ARM2_Flag (MAILBOX_BASE + 0x20) + +#elif defined(CONFIG_ARCH_OMAP2) + +/* + * Mailbox: L4 peripheral -- use omap_readX(), omap_writeX() + */ +#define OMAP24XX_MAILBOX_BASE (L4_24XX_BASE + 0x94000) + +#define MAILBOX_REVISION (OMAP24XX_MAILBOX_BASE + 0x00) +#define MAILBOX_SYSCONFIG (OMAP24XX_MAILBOX_BASE + 0x10) +#define MAILBOX_SYSSTATUS (OMAP24XX_MAILBOX_BASE + 0x14) +#define MAILBOX_MESSAGE_0 (OMAP24XX_MAILBOX_BASE + 0x40) +#define MAILBOX_MESSAGE_1 (OMAP24XX_MAILBOX_BASE + 0x44) +#define MAILBOX_MESSAGE_2 (OMAP24XX_MAILBOX_BASE + 0x48) +#define MAILBOX_MESSAGE_3 (OMAP24XX_MAILBOX_BASE + 0x4c) +#define MAILBOX_MESSAGE_4 (OMAP24XX_MAILBOX_BASE + 0x50) +#define MAILBOX_MESSAGE_5 (OMAP24XX_MAILBOX_BASE + 0x54) +#define MAILBOX_FIFOSTATUS_0 (OMAP24XX_MAILBOX_BASE + 0x80) +#define MAILBOX_FIFOSTATUS_1 (OMAP24XX_MAILBOX_BASE + 0x84) +#define MAILBOX_FIFOSTATUS_2 (OMAP24XX_MAILBOX_BASE + 0x88) +#define MAILBOX_FIFOSTATUS_3 (OMAP24XX_MAILBOX_BASE + 0x8c) +#define MAILBOX_FIFOSTATUS_4 (OMAP24XX_MAILBOX_BASE + 0x90) +#define MAILBOX_FIFOSTATUS_5 (OMAP24XX_MAILBOX_BASE + 0x94) +#define MAILBOX_MSGSTATUS_0 (OMAP24XX_MAILBOX_BASE + 0xc0) +#define MAILBOX_MSGSTATUS_1 (OMAP24XX_MAILBOX_BASE + 0xc4) +#define MAILBOX_MSGSTATUS_2 (OMAP24XX_MAILBOX_BASE + 0xc8) +#define MAILBOX_MSGSTATUS_3 (OMAP24XX_MAILBOX_BASE + 0xcc) +#define MAILBOX_MSGSTATUS_4 (OMAP24XX_MAILBOX_BASE + 0xd0) +#define MAILBOX_MSGSTATUS_5 (OMAP24XX_MAILBOX_BASE + 0xd4) +#define MAILBOX_IRQSTATUS_0 (OMAP24XX_MAILBOX_BASE + 0x100) +#define MAILBOX_IRQENABLE_0 (OMAP24XX_MAILBOX_BASE + 0x104) +#define MAILBOX_IRQSTATUS_1 (OMAP24XX_MAILBOX_BASE + 0x108) +#define MAILBOX_IRQENABLE_1 (OMAP24XX_MAILBOX_BASE + 0x10c) +#define MAILBOX_IRQSTATUS_2 (OMAP24XX_MAILBOX_BASE + 0x110) +#define MAILBOX_IRQENABLE_2 (OMAP24XX_MAILBOX_BASE + 0x114) +#define MAILBOX_IRQSTATUS_3 (OMAP24XX_MAILBOX_BASE + 0x118) +#define MAILBOX_IRQENABLE_3 (OMAP24XX_MAILBOX_BASE + 0x11c) + +#define MAILBOX_IRQ_NOTFULL(n) (1<<(2*(n)+1)) +#define MAILBOX_IRQ_NEWMSG(n) (1<<(2*(n))) + +#endif /* CONFIG_ARCH_OMAP2 */ diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h deleted file mode 100644 index 06dad83dd41..00000000000 --- a/include/asm-arm/arch-omap/dsp.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * linux/include/asm-arm/arch-omap/dsp.h - * - * Header for OMAP DSP driver - * - * Copyright (C) 2002-2005 Nokia Corporation - * - * Written by Toshihiro Kobayashi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * 2005/06/01: DSP Gateway version 3.3 - */ - -#ifndef ASM_ARCH_DSP_H -#define ASM_ARCH_DSP_H - - -/* - * for /dev/dspctl/ctl - */ -#define OMAP_DSP_IOCTL_RESET 1 -#define OMAP_DSP_IOCTL_RUN 2 -#define OMAP_DSP_IOCTL_SETRSTVECT 3 -#define OMAP_DSP_IOCTL_CPU_IDLE 4 -#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5 -#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6 -#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7 -#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8 -#define OMAP_DSP_IOCTL_GBL_IDLE 9 -#define OMAP_DSP_IOCTL_DSPCFG 10 -#define OMAP_DSP_IOCTL_DSPUNCFG 11 -#define OMAP_DSP_IOCTL_TASKCNT 12 -#define OMAP_DSP_IOCTL_POLL 13 -#define OMAP_DSP_IOCTL_REGMEMR 40 -#define OMAP_DSP_IOCTL_REGMEMW 41 -#define OMAP_DSP_IOCTL_REGIOR 42 -#define OMAP_DSP_IOCTL_REGIOW 43 -#define OMAP_DSP_IOCTL_GETVAR 44 -#define OMAP_DSP_IOCTL_SETVAR 45 -#define OMAP_DSP_IOCTL_RUNLEVEL 50 -#define OMAP_DSP_IOCTL_SUSPEND 51 -#define OMAP_DSP_IOCTL_RESUME 52 -#define OMAP_DSP_IOCTL_FBEN 53 -#define OMAP_DSP_IOCTL_FBDIS 54 -#define OMAP_DSP_IOCTL_MBSEND 99 - -/* - * for taskdev - * (ioctls below should be >= 0x10000) - */ -#define OMAP_DSP_TASK_IOCTL_BFLSH 0x10000 -#define OMAP_DSP_TASK_IOCTL_SETBSZ 0x10001 -#define OMAP_DSP_TASK_IOCTL_LOCK 0x10002 -#define OMAP_DSP_TASK_IOCTL_UNLOCK 0x10003 -#define OMAP_DSP_TASK_IOCTL_GETNAME 0x10004 - -/* - * for /dev/dspctl/mem - */ -#define OMAP_DSP_MEM_IOCTL_EXMAP 1 -#define OMAP_DSP_MEM_IOCTL_EXUNMAP 2 -#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3 -#define OMAP_DSP_MEM_IOCTL_FBEXPORT 5 -#define OMAP_DSP_MEM_IOCTL_MMUITACK 7 -#define OMAP_DSP_MEM_IOCTL_MMUINIT 9 -#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE 11 -#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE 12 - -struct omap_dsp_mapinfo { - unsigned long dspadr; - unsigned long size; -}; - -/* - * for /dev/dspctl/twch - */ -#define OMAP_DSP_TWCH_IOCTL_MKDEV 1 -#define OMAP_DSP_TWCH_IOCTL_RMDEV 2 -#define OMAP_DSP_TWCH_IOCTL_TADD 11 -#define OMAP_DSP_TWCH_IOCTL_TDEL 12 -#define OMAP_DSP_TWCH_IOCTL_TKILL 13 - -#define OMAP_DSP_DEVSTATE_NOTASK 0x00000001 -#define OMAP_DSP_DEVSTATE_ATTACHED 0x00000002 -#define OMAP_DSP_DEVSTATE_GARBAGE 0x00000004 -#define OMAP_DSP_DEVSTATE_INVALID 0x00000008 -#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100 -#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200 -#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000 -#define OMAP_DSP_DEVSTATE_ADDING 0x00010000 -#define OMAP_DSP_DEVSTATE_DELING 0x00020000 -#define OMAP_DSP_DEVSTATE_KILLING 0x00040000 -#define OMAP_DSP_DEVSTATE_STATE_MASK 0x7fffffff -#define OMAP_DSP_DEVSTATE_STALE 0x80000000 - -struct omap_dsp_taddinfo { - unsigned char minor; - unsigned long taskadr; -}; -#define OMAP_DSP_TADD_ABORTADR 0xffffffff - - -/* - * error cause definition (for error detection device) - */ -#define OMAP_DSP_ERRDT_WDT 0x00000001 -#define OMAP_DSP_ERRDT_MMU 0x00000002 - - -/* - * mailbox protocol definitions - */ - -struct omap_dsp_mailbox_cmd { - unsigned short cmd; - unsigned short data; -}; - -struct omap_dsp_reginfo { - unsigned short adr; - unsigned short val; -}; - -struct omap_dsp_varinfo { - unsigned char varid; - unsigned short val[0]; -}; - -#define OMAP_DSP_MBPROT_REVISION 0x0019 - -#define OMAP_DSP_MBCMD_WDSND 0x10 -#define OMAP_DSP_MBCMD_WDREQ 0x11 -#define OMAP_DSP_MBCMD_BKSND 0x20 -#define OMAP_DSP_MBCMD_BKREQ 0x21 -#define OMAP_DSP_MBCMD_BKYLD 0x23 -#define OMAP_DSP_MBCMD_BKSNDP 0x24 -#define OMAP_DSP_MBCMD_BKREQP 0x25 -#define OMAP_DSP_MBCMD_TCTL 0x30 -#define OMAP_DSP_MBCMD_TCTLDATA 0x31 -#define OMAP_DSP_MBCMD_POLL 0x32 -#define OMAP_DSP_MBCMD_WDT 0x50 /* v3.3: obsolete */ -#define OMAP_DSP_MBCMD_RUNLEVEL 0x51 -#define OMAP_DSP_MBCMD_PM 0x52 -#define OMAP_DSP_MBCMD_SUSPEND 0x53 -#define OMAP_DSP_MBCMD_KFUNC 0x54 -#define OMAP_DSP_MBCMD_TCFG 0x60 -#define OMAP_DSP_MBCMD_TADD 0x62 -#define OMAP_DSP_MBCMD_TDEL 0x63 -#define OMAP_DSP_MBCMD_TSTOP 0x65 -#define OMAP_DSP_MBCMD_DSPCFG 0x70 -#define OMAP_DSP_MBCMD_REGRW 0x72 -#define OMAP_DSP_MBCMD_GETVAR 0x74 -#define OMAP_DSP_MBCMD_SETVAR 0x75 -#define OMAP_DSP_MBCMD_ERR 0x78 -#define OMAP_DSP_MBCMD_DBG 0x79 - -#define OMAP_DSP_MBCMD_TCTL_TINIT 0x0000 -#define OMAP_DSP_MBCMD_TCTL_TEN 0x0001 -#define OMAP_DSP_MBCMD_TCTL_TDIS 0x0002 -#define OMAP_DSP_MBCMD_TCTL_TCLR 0x0003 -#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004 - -#define OMAP_DSP_MBCMD_RUNLEVEL_USER 0x01 -#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER 0x0e -#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY 0x10 - -#define OMAP_DSP_MBCMD_PM_DISABLE 0x00 -#define OMAP_DSP_MBCMD_PM_ENABLE 0x01 - -#define OMAP_DSP_MBCMD_KFUNC_FBCTL 0x00 -#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01 - -#define OMAP_DSP_MBCMD_FBCTL_UPD 0x0000 -#define OMAP_DSP_MBCMD_FBCTL_ENABLE 0x0002 -#define OMAP_DSP_MBCMD_FBCTL_DISABLE 0x0003 - -#define OMAP_DSP_MBCMD_AUDIO_PWR_UP 0x0000 -#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001 -#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002 - -#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000 -#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001 - -#define OMAP_DSP_MBCMD_DSPCFG_REQ 0x00 -#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH 0x28 -#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL 0x29 -#define OMAP_DSP_MBCMD_DSPCFG_PROTREV 0x70 -#define OMAP_DSP_MBCMD_DSPCFG_ABORT 0x78 -#define OMAP_DSP_MBCMD_DSPCFG_LAST 0x80 - -#define OMAP_DSP_MBCMD_REGRW_MEMR 0x00 -#define OMAP_DSP_MBCMD_REGRW_MEMW 0x01 -#define OMAP_DSP_MBCMD_REGRW_IOR 0x02 -#define OMAP_DSP_MBCMD_REGRW_IOW 0x03 -#define OMAP_DSP_MBCMD_REGRW_DATA 0x04 - -#define OMAP_DSP_MBCMD_VARID_ICRMASK 0x00 -#define OMAP_DSP_MBCMD_VARID_LOADINFO 0x01 - -#define OMAP_DSP_TTYP_ARCV 0x0001 -#define OMAP_DSP_TTYP_ASND 0x0002 -#define OMAP_DSP_TTYP_BKMD 0x0004 -#define OMAP_DSP_TTYP_BKDM 0x0008 -#define OMAP_DSP_TTYP_PVMD 0x0010 -#define OMAP_DSP_TTYP_PVDM 0x0020 - -#define OMAP_DSP_EID_BADTID 0x10 -#define OMAP_DSP_EID_BADTCN 0x11 -#define OMAP_DSP_EID_BADBID 0x20 -#define OMAP_DSP_EID_BADCNT 0x21 -#define OMAP_DSP_EID_NOTLOCKED 0x22 -#define OMAP_DSP_EID_STVBUF 0x23 -#define OMAP_DSP_EID_BADADR 0x24 -#define OMAP_DSP_EID_BADTCTL 0x30 -#define OMAP_DSP_EID_BADPARAM 0x50 -#define OMAP_DSP_EID_FATAL 0x58 -#define OMAP_DSP_EID_NOMEM 0xc0 -#define OMAP_DSP_EID_NORES 0xc1 -#define OMAP_DSP_EID_IPBFULL 0xc2 -#define OMAP_DSP_EID_WDT 0xd0 -#define OMAP_DSP_EID_TASKNOTRDY 0xe0 -#define OMAP_DSP_EID_TASKBSY 0xe1 -#define OMAP_DSP_EID_TASKERR 0xef -#define OMAP_DSP_EID_BADCFGTYP 0xf0 -#define OMAP_DSP_EID_DEBUG 0xf8 -#define OMAP_DSP_EID_BADSEQ 0xfe -#define OMAP_DSP_EID_BADCMD 0xff - -#define OMAP_DSP_TNM_LEN 16 - -#define OMAP_DSP_TID_FREE 0xff -#define OMAP_DSP_TID_ANON 0xfe - -#define OMAP_DSP_BID_NULL 0xffff -#define OMAP_DSP_BID_PVT 0xfffe - -#endif /* ASM_ARCH_DSP_H */ diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h index 16a459dfa71..2a851ebe675 100644 --- a/include/asm-arm/arch-omap/dsp_common.h +++ b/include/asm-arm/arch-omap/dsp_common.h @@ -1,36 +1,35 @@ /* - * linux/include/asm-arm/arch-omap/dsp_common.h + * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1) * - * Header for OMAP DSP subsystem control + * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved. * - * Copyright (C) 2004,2005 Nokia Corporation + * Contact: Toshihiro Kobayashi * - * Written by Toshihiro Kobayashi + * 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 free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 2005/06/03: DSP Gateway version 3.3 */ #ifndef ASM_ARCH_DSP_COMMON_H #define ASM_ARCH_DSP_COMMON_H +#ifdef CONFIG_ARCH_OMAP1 extern void omap_dsp_request_mpui(void); extern void omap_dsp_release_mpui(void); extern int omap_dsp_request_mem(void); extern int omap_dsp_release_mem(void); +#endif extern void (*omap_dsp_audio_pwr_up_request)(int stage); extern void (*omap_dsp_audio_pwr_down_request)(int stage); diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h index 78f68e6a4f0..4aca7e3d756 100644 --- a/include/asm-arm/arch-omap/io.h +++ b/include/asm-arm/arch-omap/io.h @@ -77,6 +77,17 @@ #define io_p2v(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */ #define io_v2p(va) ((va) - IO_OFFSET) /* Works for L3 and L4 */ +/* DSP */ +#define DSP_MEM_24XX_PHYS OMAP24XX_DSP_MEM_BASE /* 0x58000000 */ +#define DSP_MEM_24XX_VIRT 0xe0000000 +#define DSP_MEM_24XX_SIZE 0x28000 +#define DSP_IPI_24XX_PHYS OMAP24XX_DSP_IPI_BASE /* 0x59000000 */ +#define DSP_IPI_24XX_VIRT 0xe1000000 +#define DSP_IPI_24XX_SIZE SZ_4K +#define DSP_MMU_24XX_PHYS OMAP24XX_DSP_MMU_BASE /* 0x5a000000 */ +#define DSP_MMU_24XX_VIRT 0xe2000000 +#define DSP_MMU_24XX_SIZE SZ_4K + #endif #ifndef __ASSEMBLER__ diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h index c5bb05a69b8..db940fbafe8 100644 --- a/include/asm-arm/arch-omap/irqs.h +++ b/include/asm-arm/arch-omap/irqs.h @@ -37,8 +37,6 @@ #define INT_DSP_MMU_ABORT 7 #define INT_HOST 8 #define INT_ABORT 9 -#define INT_DSP_MAILBOX1 10 -#define INT_DSP_MAILBOX2 11 #define INT_BRIDGE_PRIV 13 #define INT_GPIO_BANK1 14 #define INT_UART3 15 @@ -63,6 +61,8 @@ #define INT_1510_RES2 2 #define INT_1510_SPI_TX 4 #define INT_1510_SPI_RX 5 +#define INT_1510_DSP_MAILBOX1 10 +#define INT_1510_DSP_MAILBOX2 11 #define INT_1510_RES12 12 #define INT_1510_LB_MMU 17 #define INT_1510_RES18 18 @@ -75,6 +75,8 @@ #define INT_1610_IH2_FIQ 2 #define INT_1610_McBSP2_TX 4 #define INT_1610_McBSP2_RX 5 +#define INT_1610_DSP_MAILBOX1 10 +#define INT_1610_DSP_MAILBOX2 11 #define INT_1610_LCD_LINE 12 #define INT_1610_GPTIMER1 17 #define INT_1610_GPTIMER2 18 @@ -131,11 +133,11 @@ #define INT_RTC_TIMER (25 + IH2_BASE) #define INT_RTC_ALARM (26 + IH2_BASE) #define INT_MEM_STICK (27 + IH2_BASE) -#define INT_DSP_MMU (28 + IH2_BASE) /* * OMAP-1510 specific IRQ numbers for interrupt handler 2 */ +#define INT_1510_DSP_MMU (28 + IH2_BASE) #define INT_1510_COM_SPI_RO (31 + IH2_BASE) /* @@ -146,6 +148,7 @@ #define INT_1610_USB_OTG (8 + IH2_BASE) #define INT_1610_SoSSI (9 + IH2_BASE) #define INT_1610_SoSSI_MATCH (19 + IH2_BASE) +#define INT_1610_DSP_MMU (28 + IH2_BASE) #define INT_1610_McBSP2RX_OF (31 + IH2_BASE) #define INT_1610_STI (32 + IH2_BASE) #define INT_1610_STI_WAKEUP (33 + IH2_BASE) @@ -239,10 +242,14 @@ #define INT_24XX_SDMA_IRQ3 15 #define INT_24XX_CAM_IRQ 24 #define INT_24XX_DSS_IRQ 25 +#define INT_24XX_MAIL_U0_MPU 26 +#define INT_24XX_DSP_UMA 27 +#define INT_24XX_DSP_MMU 28 #define INT_24XX_GPIO_BANK1 29 #define INT_24XX_GPIO_BANK2 30 #define INT_24XX_GPIO_BANK3 31 #define INT_24XX_GPIO_BANK4 32 +#define INT_24XX_MAIL_U3_MPU 34 #define INT_24XX_GPTIMER1 37 #define INT_24XX_GPTIMER2 38 #define INT_24XX_GPTIMER3 39 diff --git a/include/asm-arm/arch-omap/mailbox.h b/include/asm-arm/arch-omap/mailbox.h new file mode 100644 index 00000000000..b677918eb2a --- /dev/null +++ b/include/asm-arm/arch-omap/mailbox.h @@ -0,0 +1,54 @@ +/* mailbox.h */ + +#ifndef MAILBOX_H +#define MAILBOX_H + +typedef u32 mbx_msg_t; +typedef void (mbx_receiver_t)(mbx_msg_t msg); + +struct mbx; /* contents are private */ + +struct mbx *mbx_get(const char *id); +extern int mbx_send(struct mbx *mbx_h, mbx_msg_t msg); +extern int register_mbx_receiver(struct mbx *mbx, unsigned char cmd, + mbx_receiver_t *rcv); +extern int unregister_mbx_receiver(struct mbx *mbx, unsigned char cmd, + mbx_receiver_t *rcv); +extern void enable_mbx_irq(struct mbx *mbx); +extern void disable_mbx_irq(struct mbx *mbx); +extern void mbx_init_seq(struct mbx *mbx); + +/* + * mailbox command: 0x00 - 0x7f + * when a driver wants to use mailbox, it must reserve mailbox commands here. + */ +#define MBX_CMD_MAX 0x80 + +/* DSP Gateway */ +#define MBX_CMD_DSP_WDSND 0x10 +#define MBX_CMD_DSP_WDREQ 0x11 +#define MBX_CMD_DSP_BKSND 0x20 +#define MBX_CMD_DSP_BKREQ 0x21 +#define MBX_CMD_DSP_BKYLD 0x23 +#define MBX_CMD_DSP_BKSNDP 0x24 +#define MBX_CMD_DSP_BKREQP 0x25 +#define MBX_CMD_DSP_TCTL 0x30 +#define MBX_CMD_DSP_TCTLDATA 0x31 +#define MBX_CMD_DSP_POLL 0x32 +#define MBX_CMD_DSP_WDT 0x50 +#define MBX_CMD_DSP_RUNLEVEL 0x51 +#define MBX_CMD_DSP_PM 0x52 +#define MBX_CMD_DSP_SUSPEND 0x53 +#define MBX_CMD_DSP_KFUNC 0x54 +#define MBX_CMD_DSP_TCFG 0x60 +#define MBX_CMD_DSP_TADD 0x62 +#define MBX_CMD_DSP_TDEL 0x63 +#define MBX_CMD_DSP_TSTOP 0x65 +#define MBX_CMD_DSP_DSPCFG 0x70 +#define MBX_CMD_DSP_REGRW 0x72 +#define MBX_CMD_DSP_GETVAR 0x74 +#define MBX_CMD_DSP_SETVAR 0x75 +#define MBX_CMD_DSP_ERR 0x78 +#define MBX_CMD_DSP_DBG 0x79 + +#endif /* MAILBOX_H */ diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h index 993572cfc1c..b70063376f0 100644 --- a/include/asm-arm/arch-omap/omap24xx.h +++ b/include/asm-arm/arch-omap/omap24xx.h @@ -22,5 +22,11 @@ #define OMAP242X_CONTROL_STATUS (L4_24XX_BASE + 0x2f8) +/* DSP SS */ +#define OMAP24XX_DSP_BASE 0x58000000 +#define OMAP24XX_DSP_MEM_BASE (OMAP24XX_DSP_BASE + 0x0) +#define OMAP24XX_DSP_IPI_BASE (OMAP24XX_DSP_BASE + 0x1000000) +#define OMAP24XX_DSP_MMU_BASE (OMAP24XX_DSP_BASE + 0x2000000) + #endif /* __ASM_ARCH_OMAP24XX_H */ -- 2.41.0