#include "../plat-omap/dsp/dsp_common.h"
+static struct dsp_platform_data dsp_pdata = {
+ .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
+};
+
static struct resource omap_dsp_resources[] = {
{
.name = "dsp_mmu",
.id = -1,
.num_resources = ARRAY_SIZE(omap_dsp_resources),
.resource = omap_dsp_resources,
+ .dev = {
+ .platform_data = &dsp_pdata,
+ },
};
-
static inline void omap_init_dsp(void)
{
struct resource *res;
platform_device_register(&omap_dsp_device);
}
+
+int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
+{
+ static DEFINE_MUTEX(dsp_pdata_lock);
+
+ mutex_init(&kdev->lock);
+
+ mutex_lock(&dsp_pdata_lock);
+ list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+ mutex_unlock(&dsp_pdata_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(dsp_kfunc_device_register);
+
#else
static inline void omap_init_dsp(void) { }
-#endif
+#endif /* CONFIG_OMAP_DSP */
/*-------------------------------------------------------------------------*/
-
#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
#define OMAP1_I2C_BASE 0xfffb3800
u16 *argv;
};
-extern struct mbox *mbox_dsp;
extern void dsp_mbox_start(void);
extern void dsp_mbox_stop(void);
extern int dsp_mbox_config(void *p);
extern char *subcmd_name(struct mbcmd *mb);
extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
-
-extern struct device *dsp_device;
__dsp_core_enable();
#endif
cpustat.stat = CPUSTAT_RUN;
- enable_irq(dsp_mmu_irq);
+ enable_irq(omap_dsp->mmu_irq);
}
return;
}
/* cpustat.req < CPUSTAT_RUN */
if (cpustat.stat == CPUSTAT_RUN) {
- disable_irq(dsp_mmu_irq);
+ disable_irq(omap_dsp->mmu_irq);
#ifdef CONFIG_ARCH_OMAP1
clk_disable(api_ck_handle);
#endif
}
#endif /* CONFIG_ARCH_OMAP1 */
-/*
- * Audio power control function prototypes and defaults
- * (To be overridden with board specific functions)
- */
-static void generic_audio_pwr_up_request(int stage)
-{
- printk(KERN_ERR "audio power-up request function is not defined.\n");
-}
-
-void (*omap_dsp_audio_pwr_up_request)(int stage) = generic_audio_pwr_up_request;
-EXPORT_SYMBOL(omap_dsp_audio_pwr_up_request);
-
-static void generic_audio_pwr_down_request(int stage)
-{
- printk(KERN_ERR "audio power-down request function is not defined.\n");
-}
-
-void (*omap_dsp_audio_pwr_down_request)(int stage) = generic_audio_pwr_down_request;
-EXPORT_SYMBOL(omap_dsp_audio_pwr_down_request);
-
arch_initcall(omap_dsp_init);
#ifdef CONFIG_ARCH_OMAP1
}
#endif
-extern int dsp_mmu_irq;
+struct dsp_kfunc_device {
+ char *name;
+ struct clk *fck;
+ struct clk *ick;;
+ struct mutex lock;
+ int enabled;
+ int type;
+#define DSP_KFUNC_DEV_TYPE_COMMON 1
+#define DSP_KFUNC_DEV_TYPE_AUDIO 2
+
+ struct list_head entry;
+
+ int (*probe)(struct dsp_kfunc_device *);
+ int (*remove)(struct dsp_kfunc_device *);
+ int (*enable)(struct dsp_kfunc_device *, int);
+ int (*disable)(struct dsp_kfunc_device *, int);
+};
+
+extern int dsp_kfunc_device_register(struct dsp_kfunc_device *);
+
+struct dsp_platform_data {
+ struct list_head kdev_list;
+};
+
+struct omap_dsp {
+ struct mutex lock;
+ int enabled; /* stored peripheral status */
+ int mmu_irq;
+ struct omap_mbox *mbox;
+ struct device *dev;
+ struct list_head *kdev_list;
+};
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define command_dvfs_stop(m) (0)
+#define command_dvfs_start(m) (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define command_dvfs_stop(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_STOP))
+#define command_dvfs_start(m) \
+ (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_START))
+#endif
+
+extern struct omap_dsp *omap_dsp;
#endif /* DRIVER_DSP_COMMON_H */
MODULE_DESCRIPTION("OMAP DSP driver module");
MODULE_LICENSE("GPL");
-struct device *dsp_device;
-int dsp_mmu_irq;
-
-struct omap_mbox *mbox_dsp;
+struct omap_dsp *omap_dsp;
static struct sync_seq *mbseq;
static u16 mbseq_expect_tmp;
static u16 *mbseq_expect = &mbseq_expect_tmp;
[MBOX_CMD_DSP_DBG] = &cif_dbg,
};
+static int dsp_kfunc_probe_devices(struct omap_dsp *dsp)
+{
+ struct dsp_kfunc_device *p;
+ int ret, fail = 0;
+
+ mutex_lock(&dsp->lock);
+ list_for_each_entry(p, dsp->kdev_list, entry) {
+ if (p->probe == NULL)
+ continue;
+ ret = p->probe(p);
+ if (ret) {
+ printk(KERN_ERR
+ "probing %s failed\n", p->name);
+ fail++;
+ }
+ }
+ mutex_unlock(&dsp->lock);
+
+ pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+ return fail;
+}
+
+static int dsp_kfunc_remove_devices(struct omap_dsp *dsp)
+{
+ struct dsp_kfunc_device *p;
+ int ret, fail = 0;
+
+ mutex_lock(&dsp->lock);
+ list_for_each_entry_reverse(p, dsp->kdev_list, entry) {
+ if (p->remove == NULL)
+ continue;
+ ret = p->remove(p);
+ if (ret) {
+ printk(KERN_ERR
+ "removing %s failed\n", p->name);
+ fail++;
+ }
+ }
+ mutex_unlock(&dsp->lock);
+
+ pr_debug("%s() fail:%d\n", __FUNCTION__, fail);
+
+ return fail;
+}
+
+static int dsp_kfunc_enable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+ struct dsp_kfunc_device *p;
+ int ret, fail = 0;
+
+ mutex_lock(&dsp->lock);
+ list_for_each_entry(p, dsp->kdev_list, entry) {
+ if ((p->type != type) || (p->enable == NULL))
+ continue;
+ ret = p->enable(p, stage);
+ if (ret) {
+ printk(KERN_ERR
+ "enabling %s failed\n", p->name);
+ fail++;
+ }
+ }
+ mutex_unlock(&dsp->lock);
+
+ pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+ return fail;
+}
+
+static int dsp_kfunc_disable_devices(struct omap_dsp *dsp, int type, int stage)
+{
+ struct dsp_kfunc_device *p;
+ int ret, fail = 0;
+
+ mutex_lock(&dsp->lock);
+ list_for_each_entry_reverse(p, omap_dsp->kdev_list, entry) {
+ if ((p->type != type) || (p->disable == NULL))
+ continue;
+ ret = p->disable(p, stage);
+ if (ret) {
+ printk(KERN_ERR
+ "disabling %s failed\n", p->name);
+ fail++;
+ }
+ }
+ mutex_unlock(&dsp->lock);
+
+ pr_debug("%s(%d) fail:%d\n", __FUNCTION__, type, fail);
+
+ return fail;
+}
+
int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
{
int try;
udelay(1);
if (*(volatile u16 *)adr == val) {
/* success! */
- printk(KERN_INFO
- "omapdsp: sync_with_dsp(): try = %d\n", try);
+ pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
return 0;
}
}
{
int ret = 0;
+ if (unlikely(omap_dsp->enabled == 0)) {
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 1;
+ }
+
/*
* while MMU fault is set,
* only recovery command can be executed
if (arg)
dsp_mem_enable(ipbuf_sys_ad);
- ret = omap_mbox_msg_send(mbox_dsp, *(mbox_msg_t *)mb, (void*)arg);
+ ret = omap_mbox_msg_send(omap_dsp->mbox,
+ *(mbox_msg_t *)mb, (void*)arg);
if (ret)
goto out;
void dsp_mbox_start(void)
{
- omap_mbox_init_seq(mbox_dsp);
+ omap_mbox_init_seq(omap_dsp->mbox);
mbseq_expect_tmp = 0;
}
static int __init dsp_mbox_init(void)
{
- mbox_dsp->mbox = omap_mbox_get("dsp");
- if (IS_ERR(mbox_dsp)) {
+ omap_dsp->mbox = omap_mbox_get("dsp");
+ if (IS_ERR(omap_dsp->mbox)) {
printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
return -ENODEV;
}
- mbox_dsp->msg_receive_cb = mbcmd_receiver;
- mbox_dsp->msg_sender_cb = mbcmd_sender_prepare;
+ omap_dsp->mbox->msg_receive_cb = mbcmd_receiver;
+ omap_dsp->mbox->msg_sender_cb = mbcmd_sender_prepare;
return 0;
}
static void dsp_mbox_exit(void)
{
- mbox_dsp->msg_sender_cb = NULL;
- mbox_dsp->msg_receive_cb = NULL;
+ omap_dsp->mbox->msg_sender_cb = NULL;
+ omap_dsp->mbox->msg_receive_cb = NULL;
if (mbsync_hold_mem_active) {
dsp_mem_disable((void *)daram_base);
}
}
-static void mbox_kfunc_audio_pwr(unsigned short data)
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
{
+ int ret = -1;
+
switch (data) {
+ case DVFS_START: /* ACK from DSP */
+ /* TBD */
+ break;
case AUDIO_PWR_UP:
- omap_dsp_audio_pwr_up_request(0);
- /* send back ack */
- mbcompose_send(KFUNC, KFUNC_AUDIO_PWR, AUDIO_PWR_UP);
+ ret = dsp_kfunc_enable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+ if (ret == 0)
+ ret++;
break;
- case AUDIO_PWR_DOWN1:
- omap_dsp_audio_pwr_down_request(1);
+ case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 1);
break;
case AUDIO_PWR_DOWN2:
- omap_dsp_audio_pwr_down_request(2);
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+ break;
+ case DSP_PWR_DOWN:
+ ret = dsp_kfunc_disable_devices(omap_dsp,
+ DSP_KFUNC_DEV_TYPE_COMMON, 0);
+ if (ret == 0)
+ omap_dsp->enabled = 0;
break;
default:
printk(KERN_ERR
- "mailbox: Unknown AUDIO_PWR from DSP: 0x%04x\n", data);
+ "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+ break;
}
+
+ if (unlikely(ret < 0)) {
+ printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+ return;
+ }
+
+ if (likely(ret == 0))
+ return;
+
+ mbcompose_send(KFUNC, KFUNC_POWER, data);
}
static void mbox_kfunc(struct mbcmd *mb)
case KFUNC_FBCTL:
mbox_kfunc_fbctl(mb);
break;
- case KFUNC_AUDIO_PWR:
- mbox_kfunc_audio_pwr(mb->data);
+ case KFUNC_POWER:
+ mbox_kfunc_power(mb->data);
break;
default:
printk(KERN_ERR
static int __init dsp_drv_probe(struct platform_device *pdev)
{
int ret;
+ struct omap_dsp *info;
+ struct dsp_platform_data *pdata = pdev->dev.platform_data;
dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
- dsp_device = &pdev->dev;
+ info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+ if (unlikely(info == NULL)) {
+ dev_dbg(&pdev->dev, "no memory for info\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, info);
+ omap_dsp = info;
- dsp_mmu_irq = platform_get_irq_byname(pdev, "dsp_mmu");
- if (dsp_mmu_irq < 0)
- return -ENXIO;
+ mutex_init(&info->lock);
+ info->dev = &pdev->dev;
+ info->kdev_list = &pdata->kdev_list;
+
+ ret = dsp_kfunc_probe_devices(info);
+ if (ret) {
+ ret = -ENXIO;
+ goto fail0;
+ }
+
+ info->mmu_irq = platform_get_irq_byname(pdev, "dsp_mmu");
+ if (unlikely(info->mmu_irq) < 0) {
+ ret = -ENXIO;
+ goto fail1;
+ }
#ifdef CONFIG_ARCH_OMAP2
clk_enable(dsp_fck_handle);
#endif
if ((ret = dsp_ctl_core_init()) < 0)
- goto fail1;
- if ((ret = dsp_mem_init()) < 0)
goto fail2;
+ if ((ret = dsp_mem_init()) < 0)
+ goto fail3;
dsp_ctl_init();
mblog_init();
if ((ret = dsp_taskmod_init()) < 0)
- goto fail3;
- if ((ret = dsp_mbox_init()) < 0)
goto fail4;
+ if ((ret = dsp_mbox_init()) < 0)
+ goto fail5;
return 0;
-fail4:
+ fail5:
dsp_taskmod_exit();
-fail3:
+ fail4:
mblog_exit();
dsp_ctl_exit();
dsp_mem_exit();
-fail2:
+ fail3:
dsp_ctl_core_exit();
-fail1:
+ fail2:
#ifdef CONFIG_ARCH_OMAP2
__dsp_per_disable();
clk_disable(dsp_ick_handle);
clk_disable(dsp_fck_handle);
#endif
+ fail1:
+ dsp_kfunc_remove_devices(info);
+ fail0:
+ kfree(info);
+
return ret;
}
static int dsp_drv_remove(struct platform_device *pdev)
{
+ struct omap_dsp *info = platform_get_drvdata(pdev);
+
dsp_cpustat_request(CPUSTAT_RESET);
dsp_cfgstat_request(CFGSTAT_CLEAN);
clk_disable(dsp_ick_handle);
clk_disable(dsp_fck_handle);
#endif
+ dsp_kfunc_remove_devices(info);
+ kfree(info);
+
return 0;
}
goto out;
/* create runtime sysfs entries */
- device_create_file(dsp_device, &dev_attr_loadinfo);
+ device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
out:
dsp_mem_disable((void *)dspmem_base);
/* FIXME: lock task module */
/* remove runtime sysfs entries */
- device_remove_file(dsp_device, &dev_attr_loadinfo);
+ device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
dsp_mbox_stop();
dsp_twch_stop();
void __init dsp_ctl_init(void)
{
- device_create_file(dsp_device, &dev_attr_ifver);
- device_create_file(dsp_device, &dev_attr_cpustat);
- device_create_file(dsp_device, &dev_attr_icrmask);
+ device_create_file(omap_dsp->dev, &dev_attr_ifver);
+ device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+ device_create_file(omap_dsp->dev, &dev_attr_icrmask);
}
void dsp_ctl_exit(void)
{
- device_remove_file(dsp_device, &dev_attr_ifver);
- device_remove_file(dsp_device, &dev_attr_cpustat);
- device_remove_file(dsp_device, &dev_attr_icrmask);
+ device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+ device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+ device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
}
#define PM_ENABLE 0x01
#define KFUNC_FBCTL 0x00
-#define KFUNC_AUDIO_PWR 0x01
+#define KFUNC_POWER 0x01
#define FBCTL_UPD 0x0000
#define FBCTL_ENABLE 0x0002
#define FBCTL_DISABLE 0x0003
-#define AUDIO_PWR_UP 0x0000
-#define AUDIO_PWR_DOWN1 0x0001
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP 0x0000 /* ARM(exe/ack) <-> DSP(req) */
+#define AUDIO_PWR_DOWN 0x0001 /* ARM(exe) <- DSP(req) */
+#define AUDIO_PWR_DOWN1 AUDIO_PWR_DOWN
#define AUDIO_PWR_DOWN2 0x0002
+#define DSP_PWR_UP 0x0003 /* ARM(exe/snd) -> DSP(exe) */
+#define DSP_PWR_DOWN 0x0004 /* ARM(exe) <- DSP(req) */
+#define DVFS_START 0x0006 /* ARM(req) <-> DSP(exe/ack)*/
+#define DVFS_STOP 0x0007 /* ARM(req) -> DSP(exe) */
#define TDEL_SAFE 0x0000
#define TDEL_KILL 0x0001
printk(KERN_DEBUG "fault address = %#08x\n",
dsp_fault_adr);
}
- enable_irq(dsp_mmu_irq);
+ enable_irq(omap_dsp->mmu_irq);
return;
}
dsp_mmu_enable();
#endif
- enable_irq(dsp_mmu_irq);
+ enable_irq(omap_dsp->mmu_irq);
}
static DECLARE_WORK(mmu_int_work, (void (*)(void *))do_mmu_int, NULL);
static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- disable_irq(dsp_mmu_irq);
+ disable_irq(omap_dsp->mmu_irq);
schedule_work(&mmu_int_work);
return IRQ_HANDLED;
}
/*
* DSP MMU interrupt setup
*/
- ret = request_irq(dsp_mmu_irq, dsp_mmu_interrupt, SA_INTERRUPT,
+ ret = request_irq(omap_dsp->mmu_irq, dsp_mmu_interrupt, SA_INTERRUPT,
"dsp_mmu", &devid_mmu);
if (ret) {
printk(KERN_ERR
}
/* MMU interrupt is not enabled until DSP runs */
- disable_irq(dsp_mmu_irq);
+ disable_irq(omap_dsp->mmu_irq);
- device_create_file(dsp_device, &dev_attr_mmu);
- device_create_file(dsp_device, &dev_attr_exmap);
- device_create_file(dsp_device, &dev_attr_mempool);
+ device_create_file(omap_dsp->dev, &dev_attr_mmu);
+ device_create_file(omap_dsp->dev, &dev_attr_exmap);
+ device_create_file(omap_dsp->dev, &dev_attr_mempool);
return 0;
void dsp_mem_exit(void)
{
- free_irq(dsp_mmu_irq, &devid_mmu);
+ free_irq(omap_dsp->mmu_irq, &devid_mmu);
/* recover disable_depth */
- enable_irq(dsp_mmu_irq);
+ enable_irq(omap_dsp->mmu_irq);
#ifdef CONFIG_ARCH_OMAP1
dsp_reset_idle_boot_base();
dspvect_page = NULL;
}
- device_remove_file(dsp_device, &dev_attr_mmu);
- device_remove_file(dsp_device, &dev_attr_exmap);
- device_remove_file(dsp_device, &dev_attr_mempool);
+ device_remove_file(omap_dsp->dev, &dev_attr_mmu);
+ device_remove_file(omap_dsp->dev, &dev_attr_exmap);
+ device_remove_file(omap_dsp->dev, &dev_attr_mempool);
}
/* DSP MMU */
static void dsp_err_mmu_set(unsigned long arg)
{
- disable_irq(dsp_mmu_irq);
+ disable_irq(omap_dsp->mmu_irq);
mmu_fadr = (u32)arg;
}
static void dsp_err_mmu_clr(void)
{
- enable_irq(dsp_mmu_irq);
+ enable_irq(omap_dsp->mmu_irq);
}
/* WDT */
{
int i;
- device_remove_file(dsp_device, &dev_attr_ipbuf);
+ device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
spin_lock(&ipb_free.lock);
RESET_IPBLINK(&ipb_free);
" %d words * %d lines at 0x%p.\n",
ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
- device_create_file(dsp_device, &dev_attr_ipbuf);
+ device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
return ret;
extern struct ipbcfg ipbcfg;
extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
-#define ipb_bsycnt_inc(ipbcfg) \
- do { \
- disable_mbox_irq(mbox_dsp); \
- (ipbcfg)->bsycnt++; \
- enable_mbox_irq(mbox_dsp); \
+#define ipb_bsycnt_inc(ipbcfg) \
+ do { \
+ disable_irq(omap_dsp->mbox->irq); \
+ (ipbcfg)->bsycnt++; \
+ enable_irq(omap_dsp->mbox->irq); \
} while(0)
-#define ipb_bsycnt_dec(ipbcfg) \
- do { \
- disable_mbox_irq(mbox_dsp); \
- (ipbcfg)->bsycnt--; \
- enable_mbox_irq(mbox_dsp); \
+#define ipb_bsycnt_dec(ipbcfg) \
+ do { \
+ disable_irq(omap_dsp->mbox->irq); \
+ (ipbcfg)->bsycnt--; \
+ enable_irq(omap_dsp->mbox->irq); \
} while(0)
#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
u16 tail;
};
-#define IPBLINK_INIT { \
+#define IPBLINK_INIT { \
.lock = SPIN_LOCK_UNLOCKED, \
.top = BID_NULL, \
.tail = BID_NULL, \
break;
case MBOX_CMD_DSP_KFUNC:
s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+ (cmd_l == KFUNC_POWER) ? "POWER":
NULL;
break;
case MBOX_CMD_DSP_DSPCFG:
void __init mblog_init(void)
{
- device_create_file(dsp_device, &dev_attr_mblog);
+ device_create_file(omap_dsp->dev, &dev_attr_mblog);
}
void mblog_exit(void)
{
- device_remove_file(dsp_device, &dev_attr_mblog);
+ device_remove_file(omap_dsp->dev, &dev_attr_mblog);
}
mutex_init(&dev->usecount_lock);
memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
- dev->dev.parent = dsp_device;
+ dev->dev.parent = omap_dsp->dev;
dev->dev.bus = &dsptask_bus;
sprintf(dev->dev.bus_id, "dsptask%d", minor);
dev->dev.release = dsptask_dev_release;
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);
-
#endif /* ASM_ARCH_DSP_COMMON_H */