Commit 09172659 authored by Toshihiro Kobayashi's avatar Toshihiro Kobayashi Committed by Tony Lindgren

ARM: OMAP: Add DSP gateway

Adds support for integrated DSP on OMAP processors.
Signed-off-by: default avatarToshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent e24e6af6
...@@ -21,3 +21,6 @@ obj-$(CONFIG_CPU_FREQ) += cpu-omap.o ...@@ -21,3 +21,6 @@ obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o
# DSP subsystem
obj-y += dsp/
config OMAP_DSP
tristate "OMAP DSP driver (DSP Gateway)"
depends on ARCH_OMAP1510 || ARCH_OMAP16XX
help
This enables OMAP DSP driver, DSP Gateway.
config OMAP_DSP_MBCMD_VERBOSE
bool "Mailbox Command Verbose LOG"
depends on OMAP_DSP
help
This enables kernel log output in the Mailbox command exchanges
in the DSP Gateway driver.
config OMAP_DSP_TASK_MULTIOPEN
bool "DSP Task Multiopen Capability"
depends on OMAP_DSP
help
This enables DSP tasks to be opened by multiple times at a time.
Otherwise, they can be opened only once at a time.
config OMAP_DSP_FBEXPORT
bool "Framebuffer export to DSP"
depends on OMAP_DSP
help
This enables to map the frame buffer to DSP.
By doing this, DSP can access the frame buffer directly without
bothering ARM.
#
# Makefile for the OMAP DSP driver.
#
# The target object and module list name.
obj-y := dsp_common.o
obj-$(CONFIG_OMAP_DSP) += dsp.o
# Declare multi-part drivers
dsp-objs := dsp_core.o ipbuf.o mblog.o task.o \
dsp_ctl_core.o dsp_ctl.o taskwatch.o error.o dsp_mem.o \
uaccess_dsp.o
/*
* linux/arch/arm/mach-omap/dsp/dsp.h
*
* Header for OMAP DSP driver
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/01/21: DSP Gateway version 3.2
*/
#include "hardware_dsp.h"
#include "dsp_common.h"
#define OLD_BINARY_SUPPORT y
#ifdef OLD_BINARY_SUPPORT
#define MBREV_3_0 0x0017
#endif
#define DSP_INIT_PAGE 0xfff000
/* idle program will be placed at IDLEPG_BASE. */
#define IDLEPG_BASE 0xfffe00
#define IDLEPG_SIZE 0x100
/*
* 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
/* keep 2 entries for OMAP_DSP_TID_FREE and OMAP_DSP_TID_ANON */
#define TASKDEV_MAX 254
#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
#define MBCMD(nm) OMAP_DSP_MBCMD_##nm
/* struct mbcmd and struct 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;
};
#define mbcmd_set(mb, h, l, d) \
do { \
(mb).cmd_h = (h); \
(mb).cmd_l = (l); \
(mb).data = (d); \
} while(0)
struct mb_exarg {
unsigned char tid;
int argc;
unsigned short *argv;
};
extern void dsp_mb_start(void);
extern void dsp_mb_stop(void);
extern void dsp_mb_config(void *sync_seq_adr);
extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid,
int try_cnt);
extern int __mbsend(struct mbcmd *mb);
extern int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg,
int recovery_flag);
#define dsp_mbsend(mb) __dsp_mbsend(mb, NULL, 0)
#define dsp_mbsend_recovery(mb) __dsp_mbsend(mb, NULL, 1)
#define dsp_mbsend_exarg(mb, arg) __dsp_mbsend(mb, arg, 0)
extern int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
wait_queue_head_t *q);
#define dsp_mbsend_and_wait(mb, q) \
__dsp_mbsend_and_wait(mb, NULL, q)
#define dsp_mbsend_and_wait_exarg(mb, arg, q) \
__dsp_mbsend_and_wait(mb, arg, q)
extern void ipbuf_start(void);
extern void ipbuf_stop(void);
extern int ipbuf_config(unsigned short ln, unsigned short lsz,
unsigned long adr);
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 void balance_ipbuf(void);
#define release_ipbuf_pvt(ipbuf_pvt) \
do { \
(ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \
} while(0)
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_task_config_all(unsigned char n);
extern void dsp_task_unconfig_all(void);
extern unsigned char 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 long taskdev_state(unsigned char minor);
extern int ipbuf_is_held(unsigned char tid, unsigned short bid);
extern int dsp_mem_enable(void *adr);
extern int dsp_mem_disable(void *adr);
extern int __dsp_mem_enable(void *adr);
extern int __dsp_mem_disable(void *adr);
extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
extern void dsp_mem_start(void);
extern void dsp_twch_start(void);
extern void dsp_twch_stop(void);
extern void dsp_twch_touch(void);
extern void dsp_err_start(void);
extern void dsp_err_stop(void);
extern void dsp_err_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);
enum cmd_l_type {
CMD_L_TYPE_NULL,
CMD_L_TYPE_TID,
CMD_L_TYPE_SUBCMD,
};
struct cmdinfo {
char *name;
enum cmd_l_type cmd_l_type;
void (*handler)(struct mbcmd *mb);
};
extern const struct cmdinfo *cmdinfo[];
#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
extern char *subcmd_name(struct mbcmd *mb);
enum mblog_dir {
MBLOG_DIR_AD,
MBLOG_DIR_DA,
};
extern void mblog_add(struct mbcmd *mb, enum mblog_dir dir);
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
extern void mblog_printcmd(struct mbcmd *mb, enum mblog_dir 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;
/*
* linux/arch/arm/mach-omap/dsp/dsp_common.c
*
* OMAP DSP driver static part
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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
*
* 2004/11/19: DSP Gateway version 3.2
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/irq.h>
#include <asm/arch/dsp.h>
#include <asm/arch/tc.h>
#include <asm/hardware/clock.h>
#include "dsp_common.h"
struct clk *dsp_ck_handle;
struct clk *api_ck_handle;
unsigned long dspmem_base, dspmem_size;
int dsp_runstat = RUNSTAT_RESET;
unsigned short dsp_icrmask = DSPREG_ICR_EMIF_IDLE_DOMAIN |
DSPREG_ICR_DPLL_IDLE_DOMAIN |
DSPREG_ICR_PER_IDLE_DOMAIN |
DSPREG_ICR_CACHE_IDLE_DOMAIN |
DSPREG_ICR_DMA_IDLE_DOMAIN |
DSPREG_ICR_CPU_IDLE_DOMAIN;
int dsp_set_rstvect(unsigned long adr)
{
unsigned long *dst_adr;
if (adr >= DSPSPACE_SIZE)
return -EINVAL;
dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
/* word swap */
*dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
/* fill 8 bytes! */
*(dst_adr+1) = 0;
/* direct boot */
omap_writew(MPUI_DSP_BOOT_CONFIG_DIRECT, MPUI_DSP_BOOT_CONFIG);
return 0;
}
static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len)
{
int i;
unsigned short *src = (unsigned short *)src_c;
int len_w;
/* len must be multiple of 2. */
if (len & 1)
BUG();
len_w = len / 2;
for (i = 0; i < len_w; i++) {
/* byte swap copy */
*dst = ((*src & 0x00ff) << 8) |
((*src & 0xff00) >> 8);
src++;
dst++;
}
}
/* program size must be multiple of 2 */
#define IDLE_TEXT_SIZE 28
#define IDLE_TEXT(icr) { \
/* disable WDT */ \
0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: mov AR3 0x3404 */ \
0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: mov *AR3 0x00f5 */ \
0x9a, /* 0x9a: port */ \
0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: mov *AR3 0x00a0 */ \
0x9a, /* 0x9a: port */ \
/* set ICR = icr */ \
0x3c, 0x1b, /* 0x3c1b: mov AR3 0x1 */ \
0xe6, 0x61, (icr), /* 0xe661**: mov *AR3, icr */ \
0x9a, /* 0x9a: port */ \
/* idle and loop forever */ \
0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: idle */ \
0x4a, 0x7a, /* 0x4a7a: b -6 (infinite loop) */ \
0x20, 0x20 /* 0x20: nop */ \
}
/*
* idle_boot base:
* Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
* This value is used before DSP Gateway driver is initialized.
* DSP Gateway driver will overwrite this value with other value,
* to avoid confliction with the user program.
*/
static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI;
void dsp_idle(void)
{
unsigned char icr;
disable_irq(INT_DSP_MMU);
preempt_disable();
__dsp_reset();
clk_use(api_ck_handle);
/*
* icr settings:
* DMA should not sleep for DARAM/SARAM access
* DPLL should not sleep for DMA.
*/
icr = dsp_icrmask &
~(DSPREG_ICR_DMA_IDLE_DOMAIN | DSPREG_ICR_DPLL_IDLE_DOMAIN) &
0xff;
{
unsigned char idle_text[IDLE_TEXT_SIZE] = IDLE_TEXT(icr);
simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
IDLE_TEXT_SIZE);
}
if (idle_boot_base == DSP_BOOT_ADR_MPUI)
omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
else
dsp_set_rstvect(idle_boot_base);
clk_unuse(api_ck_handle);
udelay(10); /* to make things stable */
__dsp_run();
dsp_runstat = RUNSTAT_IDLE;
preempt_enable();
enable_irq(INT_DSP_MMU);
}
void dsp_set_idle_boot_base(unsigned long adr, size_t size)
{
if (adr == idle_boot_base)
return;
idle_boot_base = adr;
if (size < IDLE_TEXT_SIZE) {
printk(KERN_ERR
"omapdsp: size for idle program is not enough!\n");
BUG();
}
if (dsp_runstat == RUNSTAT_IDLE)
dsp_idle();
}
static int init_done;
static int __init omap_dsp_init(void)
{
dspmem_size = 0;
#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
dspmem_base = OMAP1510_DSP_BASE;
dspmem_size = OMAP1510_DSP_SIZE;
}
#endif
#ifdef CONFIG_ARCH_OMAP16XX
if (cpu_is_omap16xx()) {
dspmem_base = OMAP16XX_DSP_BASE;
dspmem_size = OMAP16XX_DSP_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 (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");
if (IS_ERR(api_ck_handle)) {
printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
return PTR_ERR(api_ck_handle);
}
__dsp_enable();
mpui_byteswap_off();
mpui_wordswap_on();
tc_wordswap();
init_done = 1;
return 0;
}
void omap_dsp_request_idle(void)
{
if (dsp_runstat == RUNSTAT_RESET) {
if (!init_done)
omap_dsp_init();
dsp_idle();
}
}
arch_initcall(omap_dsp_init);
EXPORT_SYMBOL(omap_dsp_request_idle);
#ifdef CONFIG_OMAP_DSP_MODULE
EXPORT_SYMBOL(dsp_ck_handle);
EXPORT_SYMBOL(api_ck_handle);
EXPORT_SYMBOL(dspmem_base);
EXPORT_SYMBOL(dspmem_size);
EXPORT_SYMBOL(dsp_runstat);
EXPORT_SYMBOL(dsp_icrmask);
EXPORT_SYMBOL(dsp_set_rstvect);
EXPORT_SYMBOL(dsp_idle);
EXPORT_SYMBOL(dsp_set_idle_boot_base);
EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
#endif
/*
* linux/arch/arm/mach-omap/dsp/dsp_common.h
*
* Header for OMAP DSP driver static part
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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
*
* 2004/11/16: DSP Gateway version 3.2
*/
#include "hardware_dsp.h"
#define DSPSPACE_SIZE 0x1000000
#define omap_set_bit_regw(b,r) \
do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
#define omap_clr_bit_regw(b,r) \
do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
#define omap_set_bit_regl(b,r) \
do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
#define omap_clr_bit_regl(b,r) \
do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
#define 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 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)
/*
* MPUI byteswap/wordswap on/off
* default setting: wordswap = all, byteswap = APIMEM only
*/
#define mpui_wordswap_on() \
{ \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \
} while(0)
#define mpui_wordswap_off() \
{ \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \
} while(0)
#define mpui_byteswap_on() \
{ \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \
} while(0)
#define mpui_byteswap_off() \
{ \
omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \
} while(0)
/*
* TC wordswap on / off
*/
#define tc_wordswap() \
{ \
omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
TC_ENDIANISM); \
} while(0)
#define tc_noswap() \
{ \
omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \
TC_ENDIANISM); \
} while(0)
/*
* enable priority registers, EMIF, MPUI control logic
*/
#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
#define __dsp_disable() omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
#define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
#define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
#define RUNSTAT_RESET 0
#define RUNSTAT_IDLE 1
#define RUNSTAT_RUN 2
extern struct clk *dsp_ck_handle;
extern struct clk *api_ck_handle;
extern unsigned long dspmem_base, dspmem_size;
extern int dsp_runstat;
extern unsigned short dsp_icrmask;
int dsp_set_rstvect(unsigned long adr);
void dsp_idle(void);
void dsp_set_idle_boot_base(unsigned long adr, size_t size);
This diff is collapsed.
This diff is collapsed.
/*
* linux/arch/arm/mach-omap/dsp/dsp_ctl_core.c
*
* OMAP DSP control devices core driver
*
* Copyright (C) 2004,2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/02/10: DSP Gateway version 3.2
*/
#include <linux/module.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <asm/arch/dsp.h>
#include "hardware_dsp.h"
#define CTL_MINOR 0
#define MEM_MINOR 1
#define TWCH_MINOR 2
#define ERR_MINOR 3
static struct class_simple *dsp_ctl_class;
extern struct file_operations dsp_ctl_fops,
dsp_mem_fops,
dsp_twch_fops,
dsp_err_fops;
static int dsp_ctl_core_open(struct inode *inode, struct file *file)
{
switch (iminor(inode)) {
case CTL_MINOR:
file->f_op = &dsp_ctl_fops;
break;
case MEM_MINOR:
file->f_op = &dsp_mem_fops;
break;
case TWCH_MINOR:
file->f_op = &dsp_twch_fops;
break;
case ERR_MINOR:
file->f_op = &dsp_err_fops;
break;
default:
return -ENXIO;
}
if (file->f_op && file->f_op->open)
return file->f_op->open(inode, file);
return 0;
}
static struct file_operations dsp_ctl_core_fops = {
.owner = THIS_MODULE,
.open = dsp_ctl_core_open,
};
static const struct dev_list {
unsigned int minor;
char *devname;
char *devfs_name;
umode_t mode;
} dev_list[] = {
{CTL_MINOR, "dspctl", "dspctl/ctl", S_IRUSR | S_IWUSR},
{MEM_MINOR, "dspmem", "dspctl/mem", S_IRUSR | S_IWUSR | S_IRGRP},
{TWCH_MINOR, "dsptwch", "dspctl/twch", S_IRUSR | S_IWUSR | S_IRGRP},
{ERR_MINOR, "dsperr", "dspctl/err", S_IRUSR | S_IRGRP},
};
int __init dsp_ctl_core_init(void)
{
int retval;
int i;
retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
&dsp_ctl_core_fops);
if (retval < 0) {
printk(KERN_ERR
"omapdsp: failed to register dspctl device: %d\n",
retval);
return retval;
}
dsp_ctl_class = class_simple_create(THIS_MODULE, "dspctl");
devfs_mk_dir("dspctl");
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
class_simple_device_add(dsp_ctl_class,
MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor),
NULL, dev_list[i].devname);
devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor),
S_IFCHR | dev_list[i].mode,
dev_list[i].devfs_name);
}
return 0;
}
void dsp_ctl_core_exit(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
devfs_remove(dev_list[i].devfs_name);
class_simple_device_remove(MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor));
}
devfs_remove("dspctl");
class_simple_destroy(dsp_ctl_class);
unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
}
This diff is collapsed.
/*
* linux/arch/arm/mach-omap/dsp/error.c
*
* OMAP DSP error detection I/F device driver
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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
*
* 2004/11/22: DSP Gateway version 3.2
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/ioctls.h>
#include <asm/arch/dsp.h>
#include "dsp.h"
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 */
/*
* DSP error detection device file operations
*/
static ssize_t dsp_err_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
unsigned long flags;
int status;
if (count < 4)
return 0;
if (errcnt == 0) {
long current_state;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&err_wait_q, &wait);
current_state = current->state;
set_current_state(TASK_INTERRUPTIBLE);
if (errcnt == 0) /* last check */
schedule();
set_current_state(current_state);
remove_wait_queue(&err_wait_q, &wait);
if (signal_pending(current))
return -EINTR;
}
local_irq_save(flags);
status = copy_to_user(buf, &errcode, 4);
if (status) {
local_irq_restore(flags);
return -EFAULT;
}
errcnt = 0;
local_irq_restore(flags);
return 4;
}
static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &err_wait_q, wait);
if (errcnt != 0)
mask |= POLLIN | POLLRDNORM;
return mask;
}
struct file_operations dsp_err_fops = {
.owner = THIS_MODULE,
.poll = dsp_err_poll,
.read = dsp_err_read,
};
/*
* DSP MMU
*/
void dsp_err_mmu_set(unsigned long adr)
{
disable_irq(INT_DSP_MMU);
errcode |= OMAP_DSP_ERRDT_MMU;
errcnt++;
mmu_fadr = adr;
wake_up_interruptible(&err_wait_q);
}
void dsp_err_mmu_clear(void)
{
errcode &= ~OMAP_DSP_ERRDT_MMU;
enable_irq(INT_DSP_MMU);
}
int dsp_err_mmu_isset(void)
{
return (errcode & OMAP_DSP_ERRDT_MMU) ? 1 : 0;
}
/*
* WDT
*/
void dsp_err_wdt_clear(void)
{
errcode &= ~OMAP_DSP_ERRDT_WDT;
}
int dsp_err_wdt_isset(void)
{
return (errcode & OMAP_DSP_ERRDT_WDT) ? 1 : 0;
}
/*
* functions called from mailbox1 interrupt routine
*/
void mbx1_wdt(struct mbcmd *mb)
{
printk(KERN_WARNING "omapdsp: DSP WDT expired!\n");
errcode |= OMAP_DSP_ERRDT_WDT;
errcnt++;
wdtval = mb->data;
wake_up_interruptible(&err_wait_q);
}
extern void mbx1_err_ipbfull(void);
extern void mbx1_err_fatal(unsigned char tid);
void mbx1_err(struct mbcmd *mb)
{
unsigned char eid = mb->cmd_l;
char *eidnm = subcmd_name(mb);
unsigned char tid;
if (eidnm) {
printk(KERN_WARNING
"mbx: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
} else {
printk(KERN_WARNING
"mbx: ERR from DSP (unknown EID=%02x): %04x\n",
eid, mb->data);
}
switch (eid) {
case OMAP_DSP_EID_IPBFULL:
mbx1_err_ipbfull();
break;
case OMAP_DSP_EID_FATAL:
tid = mb->data & 0x00ff;
mbx1_err_fatal(tid);
break;
}
}
/*
*
*/
void dsp_err_start(void)
{
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)
{
wake_up_interruptible(&err_wait_q);
}
/*
* linux/arch/arm/mach-omap/dsp/fifo.h
*
* FIFO buffer operators
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/02/24: DSP Gateway version 3.2
*/
struct fifo_struct {
spinlock_t lock;
char *buf;
size_t sz;
size_t cnt;
unsigned int wp;
};
static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz)
{
if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
fifo->sz = 0;
return -ENOMEM;
}
fifo->sz = sz;
fifo->cnt = 0;
fifo->wp = 0;
return 0;
}
static inline int init_fifo(struct fifo_struct *fifo, size_t sz)
{
spin_lock_init(&fifo->lock);
return alloc_fifo(fifo, sz);
}
static inline void free_fifo(struct fifo_struct *fifo)
{
spin_lock(&fifo->lock);
if (fifo->buf == NULL)
return;
kfree(fifo->buf);
fifo->buf = NULL;
fifo->sz = 0;
spin_unlock(&fifo->lock);
}
static inline void flush_fifo(struct fifo_struct *fifo)
{
spin_lock(&fifo->lock);
fifo->cnt = 0;
fifo->wp = 0;
spin_unlock(&fifo->lock);
}
#define fifo_empty(fifo) ((fifo)->cnt == 0)
static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
{
int ret = sz;
spin_lock(&fifo->lock);
if (!fifo_empty(fifo)) {
ret = -EBUSY;
goto out;
}
/* free */
if (fifo->buf)
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;
out:
spin_unlock(&fifo->lock);
return ret;
}
static inline void write_word_to_fifo(struct fifo_struct *fifo,
unsigned short word)
{
spin_lock(&fifo->lock);
*(unsigned short *)&fifo->buf[fifo->wp] = word;
if ((fifo->wp += 2) == fifo->sz)
fifo->wp = 0;
if ((fifo->cnt += 2) > fifo->sz)
fifo->cnt = fifo->sz;
spin_unlock(&fifo->lock);
}
/*
* (before)
*
* [*******----------*************]
* ^wp
* <----------------------------> sz = 30
* <-----> <-----------> cnt = 20
*
* (read: count=16)
* <-> <-----------> count = 16
* <-----------> cnt1 = 13
* ^rp
*
* (after)
* [---****-----------------------]
* ^wp
*/
static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
size_t count)
{
int rp;
ssize_t ret;
/* fifo size can be zero */
if (fifo->sz == 0)
return 0;
spin_lock(&fifo->lock);
if (count > fifo->cnt)
count = fifo->cnt;
if ((rp = fifo->wp - fifo->cnt) >= 0) {
/* valid area is straight */
if (copy_to_user(dst, &fifo->buf[rp], count)) {
ret = -EFAULT;
goto out;
}
} else {
int cnt1 = -rp;
rp += fifo->sz;
if (cnt1 >= count) {
/* requested area is straight */
if (copy_to_user(dst, &fifo->buf[rp], count)) {
ret = -EFAULT;
goto out;
}
} else {
if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
ret = -EFAULT;
goto out;
}
if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
ret = -EFAULT;
goto out;
}
}
}
fifo->cnt -= count;
ret = count;
out:
spin_unlock(&fifo->lock);
return ret;
}
/*
* linux/arch/arm/mach-omap/dsp/hardware_dsp.h
*
* Register bit definitions for DSP driver
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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
*
* 2004/09/30: DSP Gateway version 3.2
*/
#ifndef __OMAP_DSP_HARDWARE_DSP_H
#define __OMAP_DSP_HARDWARE_DSP_H
/*
* 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_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 */
/*
* linux/arch/arm/mach-omap/dsp/ipbuf.c
*
* IPBUF handler
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/02/17: DSP Gateway version 3.2
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <asm/signal.h>
#include <asm/arch/dsp.h>
#include "dsp.h"
#include "ipbuf.h"
struct ipbuf **ipbuf;
struct ipbcfg ipbcfg;
struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
static struct ipblink ipb_free = IPBLINK_INIT;
void ipbuf_stop(void)
{
ipbcfg.ln = 0;
if (ipbuf) {
kfree(ipbuf);
ipbuf = NULL;
}
}
/*
* ipbuf_config() is called by mailbox workqueue
*/
int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr)
{
void *base;
unsigned long lsz_byte = ((unsigned long)lsz) << 1;
size_t size;
int ret = 0;
int i;
spin_lock(&ipb_free.lock);
INIT_IPBLINK(&ipb_free);
spin_unlock(&ipb_free.lock);
/*
* global IPBUF
*/
if (adr & 0x1) {
printk(KERN_ERR
"mbx: global ipbuf address (0x%08lx) is odd number!\n",
adr);
return -EINVAL;
}
size = lsz_byte * ln;
if (adr + size > DSPSPACE_SIZE) {
printk(KERN_ERR
"mbx: ipbuf address (0x%08lx) and size (0x%08x) is "
"illegal!\n", adr, size);
return -EINVAL;
}
base = dspword_to_virt(adr);
ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL);
if (ipbuf == NULL) {
printk(KERN_ERR "mbx: memory allocation for ipbuf failed.\n");
return -ENOMEM;
}
for (i = 0; i < ln; i++) {
void *top, *btm;
top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
ipbuf[i] = (struct ipbuf *)top;
if (((unsigned long)top & 0xfffe0000) !=
((unsigned long)btm & 0xfffe0000)) {
/*
* an ipbuf line should not cross
* 64k-word boundary.
*/
printk(KERN_ERR
"omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
" @0x%p, size=0x%08lx\n", i, top, lsz_byte);
ret = -EINVAL;
}
}
ipbcfg.ln = ln;
ipbcfg.lsz = lsz;
ipbcfg.adr = adr;
ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
ipbcfg.cnt_full = 0;
printk(KERN_INFO
"omapdsp: IPBUF configuration\n"
" %d words * %d lines at 0x%p.\n",
ipbcfg.lsz, ipbcfg.ln, dspword_to_virt(ipbcfg.adr));
return ret;
}
/*
* Global IPBUF operations
*/
unsigned short get_free_ipbuf(unsigned char tid)
{
unsigned short bid;
if (ipblink_empty(&ipb_free)) {
/* FIXME: wait on queue when not available. */
return OMAP_DSP_BID_NULL;
}
/*
* FIXME: dsp_enable_dspmem!
*/
spin_lock(&ipb_free.lock);
bid = ipb_free.top;
ipbuf[bid]->la = tid; /* lock */
ipblink_del_top(&ipb_free, ipbuf);
spin_unlock(&ipb_free.lock);
return bid;
}
void release_ipbuf(unsigned short bid)
{
if (ipbuf[bid]->la == OMAP_DSP_TID_FREE) {
printk(KERN_WARNING
"omapdsp: attempt to release unlocked IPBUF[%d].\n",
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);
}
static int try_yld(unsigned short bid)
{
struct mbcmd mb;
int status;
ipbuf[bid]->sa = OMAP_DSP_TID_ANON;
mbcmd_set(mb, MBCMD(BKYLD), 0, bid);
status = dsp_mbsend(&mb);
if (status < 0) {
/* DSP is busy and ARM keeps this line. */
release_ipbuf(bid);
return status;
}
ipb_bsycnt_inc(&ipbcfg);
return 0;
}
/*
* balancing ipbuf lines with DSP
*/
static void do_balance_ipbuf(void)
{
while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
unsigned short bid;
bid = get_free_ipbuf(OMAP_DSP_TID_ANON);
if (bid == OMAP_DSP_BID_NULL)
return;
if (try_yld(bid) < 0)
return;
}
}
static DECLARE_WORK(balance_ipbuf_work, (void (*)(void *))do_balance_ipbuf,
NULL);
void balance_ipbuf(void)
{
schedule_work(&balance_ipbuf_work);
}
/* for process context */
void unuse_ipbuf(unsigned short bid)
{
if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
/* we don't have enough IPBUF lines. let's keep it. */
release_ipbuf(bid);
} else {
/* we have enough IPBUF lines. let's return this line to DSP. */
ipbuf[bid]->la = OMAP_DSP_TID_ANON;
try_yld(bid);
balance_ipbuf();
}
}
/* for interrupt context */
void unuse_ipbuf_nowait(unsigned short bid)
{
release_ipbuf(bid);
balance_ipbuf();
}
/*
* functions called from mailbox1 interrupt routine
*/
void mbx1_err_ipbfull(void)
{
ipbcfg.cnt_full++;
}
/*
* sysfs files
*/
static ssize_t ipbuf_show(struct device *dev, char *buf)
{
int len = 0;
unsigned short 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;
if (len > PAGE_SIZE - 100) {
len += sprintf(buf + len, "out of buffer.\n");
goto finish;
}
len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
bid, ipbuf[bid]);
if (la == OMAP_DSP_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) {
len += sprintf(buf + len,
" Linux->DSPtask[%d] "
"(already read and now free for DSP)\n",
la);
} else if (ipbuf_is_held(ld, bid)) {
len += sprintf(buf + len,
" DSPtask[%d]->Linux "
"(waiting to be read)\n"
" count = %d\n", ld, c);
} else {
len += sprintf(buf + len,
" Linux->DSPtask[%d] "
"(waiting to be read)\n"
" count = %d\n", la, c);
}
}
len += sprintf(buf + len, "\nFree IPBUF link: ");
spin_lock(&ipb_free.lock);
ipblink_for_each(bid, &ipb_free, ipbuf) {
len += sprintf(buf + len, "%d ", bid);
}
spin_unlock(&ipb_free.lock);
len += sprintf(buf + len, "\n");
len += sprintf(buf + len, "IPBFULL error count: %ld\n",
ipbcfg.cnt_full);
finish:
return len;
}
struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
/*
* linux/arch/arm/mach-omap/dsp/ipbuf.h
*
* Header for IPBUF
*
* Copyright (C) 2002-2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/02/17: DSP Gateway version 3.2
*/
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) */
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 */
};
struct ipbuf_sys {
unsigned short s; /* sync word */
unsigned short d[15]; /* data */
};
struct ipbcfg {
unsigned short ln;
unsigned short lsz;
unsigned long adr;
unsigned short bsycnt;
unsigned long cnt_full; /* count of IPBFULL error */
};
extern struct ipbuf **ipbuf;
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); \
(ipbcfg)->bsycnt++; \
enable_irq(INT_D2A_MB1); \
} while(0)
#define ipb_bsycnt_dec(ipbcfg) \
do { \
disable_irq(INT_D2A_MB1); \
(ipbcfg)->bsycnt--; \
enable_irq(INT_D2A_MB1); \
} while(0)
#define dsp_mem_enable_ipbuf() dsp_mem_enable(dspword_to_virt(ipbcfg.adr))
#define dsp_mem_disable_ipbuf() dsp_mem_disable(dspword_to_virt(ipbcfg.adr))
struct ipblink {
spinlock_t lock;
unsigned short top;
unsigned short tail;
};
#define IPBLINK_INIT { \
.lock = SPIN_LOCK_UNLOCKED, \
.top = OMAP_DSP_BID_NULL, \
.tail = OMAP_DSP_BID_NULL, \
}
#define INIT_IPBLINK(link) \
do { \
(link)->top = OMAP_DSP_BID_NULL; \
(link)->tail = OMAP_DSP_BID_NULL; \
} while(0)
#define ipblink_empty(link) ((link)->top == OMAP_DSP_BID_NULL)
static __inline__ void ipblink_del_top(struct ipblink *link,
struct ipbuf **ipbuf)
{
struct ipbuf *bufp = ipbuf[link->top];
if ((link->top = bufp->next) == OMAP_DSP_BID_NULL)
link->tail = OMAP_DSP_BID_NULL;
else
bufp->next = OMAP_DSP_BID_NULL;
}
static __inline__ void ipblink_add_tail(struct ipblink *link,
unsigned short bid,
struct ipbuf **ipbuf)
{
if (ipblink_empty(link))
link->top = bid;
else
ipbuf[link->tail]->next = bid;
link->tail = bid;
}
static __inline__ void ipblink_add_pvt(struct ipblink *link)
{
link->top = OMAP_DSP_BID_PVT;
link->tail = OMAP_DSP_BID_PVT;
}
static __inline__ void ipblink_del_pvt(struct ipblink *link)
{
link->top = OMAP_DSP_BID_NULL;
link->tail = OMAP_DSP_BID_NULL;
}
#define ipblink_for_each(bid, link, ipbuf) \
for (bid = (link)->top; bid != OMAP_DSP_BID_NULL; bid = ipbuf[bid]->next)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -142,3 +142,5 @@ config OMAP_ARM_30MHZ ...@@ -142,3 +142,5 @@ config OMAP_ARM_30MHZ
help help
Enable 30MHz clock for OMAP CPU. If unsure, say N. Enable 30MHz clock for OMAP CPU. If unsure, say N.
source "arch/arm/mach-omap/dsp/Kconfig"
This diff is collapsed.
/*
* linux/include/asm-arm/arch-omap/dsp_common.h
*
* Header for OMAP DSP subsystem control
*
* Copyright (C) 2004,2005 Nokia Corporation
*
* Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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
*
* 2004/09/22: DSP Gateway version 3.2
*/
#ifndef ASM_ARCH_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
void omap_dsp_request_idle(void);
#endif /* ASM_ARCH_DSP_COMMON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment