From 4b35036f09f89dcc25b0a770c56e2c71d4937cb4 Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Thu, 21 Sep 2006 17:41:41 +0300 Subject: [PATCH] ARM: OMAP: mailbox restructure Mailbox is restructured as below: - OMAP1 and OMAP2 parts split out to mach-omap[1-2] respectively. - struct mbx isolation - Introduced device model - Added class interface Moved omap[1,2] specific parts in mach-omap[1,2]/ Signed-off-by: Hiroshi DOYU Signed-off-by: Juha Yrjola --- arch/arm/plat-omap/dsp/dsp_core.c | 35 +- arch/arm/plat-omap/dsp/dsp_mbcmd.h | 30 ++ arch/arm/plat-omap/dsp/dsp_mem.c | 1 - arch/arm/plat-omap/mailbox.c | 698 ++++++++++------------------- arch/arm/plat-omap/mailbox.h | 197 ++++++++ arch/arm/plat-omap/mailbox_hw.h | 79 ---- 6 files changed, 469 insertions(+), 571 deletions(-) create mode 100644 arch/arm/plat-omap/mailbox.h delete mode 100644 arch/arm/plat-omap/mailbox_hw.h diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c index b012f39d198..f0b303f9c66 100644 --- a/arch/arm/plat-omap/dsp/dsp_core.c +++ b/arch/arm/plat-omap/dsp/dsp_core.c @@ -34,12 +34,13 @@ #include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" +#include "dsp_common.h" MODULE_AUTHOR("Toshihiro Kobayashi "); MODULE_DESCRIPTION("OMAP DSP driver module"); MODULE_LICENSE("GPL"); -struct mbox *mbox_dsp; +struct omap_mbox *mbox_dsp; static struct sync_seq *mbseq; static u16 mbseq_expect_tmp; static u16 *mbseq_expect = &mbseq_expect_tmp; @@ -204,7 +205,7 @@ int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg, mblog_add(mb, DIR_A2D); - ret = mbox_send(mbox_dsp, *(mbox_msg_t *)mb); + ret = omap_mbox_msg_send(mbox_dsp, *(mbox_msg_t *)mb); out: mutex_unlock(&mbsend_lock); @@ -261,7 +262,7 @@ static int mbsync_hold_mem_active; void dsp_mbox_start(void) { - mbox_init_seq(mbox_dsp); + omap_mbox_init_seq(mbox_dsp); mbseq_expect_tmp = 0; } @@ -301,34 +302,20 @@ int dsp_mbox_config(void *p) static int __init dsp_mbox_init(void) { - int i; - int ret; - - for (i = 0; i < MBOX_CMD_MAX; i++) { - if (cmdinfo[i] != NULL) { - ret = register_mbox_receiver(mbox_dsp, i, mbcmd_receiver); - if (ret) - goto fail; - } + mbox_dsp->mbox = omap_mbox_get("dsp"); + if (IS_ERR(mbox_dsp)) { + printk(KERN_ERR "failed to get mailbox handler for DSP.\n"); + return -ENODEV; } - return 0; + mbox_dsp->mbox->msg_receive_cb = mbcmd_receiver; -fail: - for (i--; i; i--) - unregister_mbox_receiver(mbox_dsp, i, mbcmd_receiver); - - return ret; + return 0; } static void dsp_mbox_exit(void) { - int i; - - for (i = 0; i < MBOX_CMD_MAX; i++) { - if (cmdinfo[i] != NULL) - unregister_mbox_receiver(mbox_dsp, i, mbcmd_receiver); - } + mbox_dsp->mbox->msg_receive_cb = NULL; if (mbsync_hold_mem_active) { dsp_mem_disable((void *)daram_base); diff --git a/arch/arm/plat-omap/dsp/dsp_mbcmd.h b/arch/arm/plat-omap/dsp/dsp_mbcmd.h index 22b1548c637..8d4ff05cd81 100644 --- a/arch/arm/plat-omap/dsp/dsp_mbcmd.h +++ b/arch/arm/plat-omap/dsp/dsp_mbcmd.h @@ -21,6 +21,36 @@ * */ +/* + * mailbox command: 0x00 - 0x7f + * when a driver wants to use mailbox, it must reserve mailbox commands here. + */ +#define MBOX_CMD_DSP_WDSND 0x10 +#define MBOX_CMD_DSP_WDREQ 0x11 +#define MBOX_CMD_DSP_BKSND 0x20 +#define MBOX_CMD_DSP_BKREQ 0x21 +#define MBOX_CMD_DSP_BKYLD 0x23 +#define MBOX_CMD_DSP_BKSNDP 0x24 +#define MBOX_CMD_DSP_BKREQP 0x25 +#define MBOX_CMD_DSP_TCTL 0x30 +#define MBOX_CMD_DSP_TCTLDATA 0x31 +#define MBOX_CMD_DSP_POLL 0x32 +#define MBOX_CMD_DSP_WDT 0x50 +#define MBOX_CMD_DSP_RUNLEVEL 0x51 +#define MBOX_CMD_DSP_PM 0x52 +#define MBOX_CMD_DSP_SUSPEND 0x53 +#define MBOX_CMD_DSP_KFUNC 0x54 +#define MBOX_CMD_DSP_TCFG 0x60 +#define MBOX_CMD_DSP_TADD 0x62 +#define MBOX_CMD_DSP_TDEL 0x63 +#define MBOX_CMD_DSP_TSTOP 0x65 +#define MBOX_CMD_DSP_DSPCFG 0x70 +#define MBOX_CMD_DSP_REGRW 0x72 +#define MBOX_CMD_DSP_GETVAR 0x74 +#define MBOX_CMD_DSP_SETVAR 0x75 +#define MBOX_CMD_DSP_ERR 0x78 +#define MBOX_CMD_DSP_DBG 0x79 + /* * DSP mailbox protocol definitions */ diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c index eaf9caf5e0e..4b21c386385 100644 --- a/arch/arm/plat-omap/dsp/dsp_mem.c +++ b/arch/arm/plat-omap/dsp/dsp_mem.c @@ -44,7 +44,6 @@ #include #include "uaccess_dsp.h" #include "dsp_mbcmd.h" -#include "../mailbox_hw.h" #include "dsp.h" #include "ioctl.h" #include "ipbuf.h" diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index bb3ccd05931..e8ed9fba738 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -4,6 +4,7 @@ * Copyright (C) 2006 Nokia Corporation. All rights reserved. * * Contact: Toshihiro Kobayashi + * Restructured by Hiroshi DOYU * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,550 +26,313 @@ #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_mbox(m, msgp) \ - do { \ - *(msgp) = omap_readw((m)->data_r); \ - *(msgp) |= ((mbox_msg_t)omap_readw((m)->cmd_r)) << 16; \ - } while (0) -#define write_mbox(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 mbox_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_mbox(m, msgp) \ - do { *(msgp) = omap_readl((m)->message_r); } while (0) -#define write_mbox(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 mbox_nomsg(m) (omap_readl((m)->msgstatus_r) == 0) -#define mbox_is_notfull(m) (omap_readl((m)->fifostatus_w) == 0) - -#endif /* CONFIG_ARCH_OMAP2 */ - -static void do_mbox(void *p); - -#define MBQ_DEPTH 16 -struct mbq { - mbox_msg_t msg[MBQ_DEPTH]; - int rp, wp, full; -}; +#include "mailbox.h" -#define mbq_inc(p) do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0) - -#if defined(CONFIG_ARCH_OMAP1) -# define MBOX_USE_SEQ_BIT /* XXX */ -#elif defined(CONFIG_ARCH_OMAP2) -# undef MBOX_USE_SEQ_BIT -#endif - -struct mbox { - char *name; - unsigned int irq; - char irq_devid_newmsg; -#ifdef CONFIG_ARCH_OMAP2 - char irq_devid_notfull; -#endif -#ifdef MBOX_USE_SEQ_BIT - mbox_msg_t seq_snd; - mbox_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 - mbox_receiver_t *receiver_map[MBOX_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 -}; +static struct omap_mbox *mboxes; +static DEFINE_RWLOCK(mboxes_lock); -#if defined(CONFIG_ARCH_OMAP1) +static struct omap_mbox **find_mboxes(const char *name) +{ + struct omap_mbox **p; -#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 + for (p = &mboxes; *p; p = &(*p)->next) { + if (strcmp((*p)->name, name) == 0) + break; + } -static struct mbox mbox_dsp = { - .name = "DSP", - .irq = INT_DSP_MAILBOX1, - .work = __WORK_INITIALIZER(mbox_dsp.work, do_mbox, &mbox_dsp), + return p; +} - .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, -}; +struct omap_mbox *omap_mbox_get(const char *name) +{ + struct omap_mbox *mbox; -#elif defined(CONFIG_ARCH_OMAP2) + read_lock(&mboxes_lock); + mbox = *(find_mboxes(name)); + read_unlock(&mboxes_lock); + + return mbox; +} +EXPORT_SYMBOL(omap_mbox_get); + +/* Mailbox Sequence Bit function */ +void omap_mbox_init_seq(struct omap_mbox *mbox) +{ + mbox_seq_init(mbox); +} +EXPORT_SYMBOL(omap_mbox_init_seq); /* - * MAILBOX 0: ARM -> DSP, - * MAILBOX 1: ARM <- DSP. - * MAILBOX 2: ARM -> IVA, - * MAILBOX 3: ARM <- IVA. + * message sender */ -static struct mbox mbox_dsp = { - .name = "DSP", - .irq = INT_24XX_MAIL_U0_MPU, - .work = __WORK_INITIALIZER(mbox_dsp.work, do_mbox, &mbox_dsp), - .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbox_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 mbox mbox_iva = { - .name = "IVA", - .irq = INT_24XX_MAIL_U3_MPU, - .work = __WORK_INITIALIZER(mbox_iva.work, do_mbox, &mbox_iva), - .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbox_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 */ +int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) +{ + int ret; + int i = 1000; + static DEFINE_MUTEX(msg_send_lock); + + while (mbox_fifo_full(mbox)) { + if (mbox->ops->type == OMAP_MBOX_TYPE2) { + enable_mbox_irq(mbox, IRQ_TX); + wait_event_interruptible(mbox->tx_waitq, + !mbox_fifo_full(mbox)); + } else + udelay(1); + + if (--i == 0) + return -1; + } -static struct mbox *mboxes[] = { - &mbox_dsp, -#ifdef CONFIG_ARCH_OMAP2 - &mbox_iva, -#endif -}; -struct mbox *mbox_get(const char *id) -{ - int i; + mutex_lock(&msg_send_lock); - for (i = 0; i < ARRAY_SIZE(mboxes); i++) { - if (!strcmp(id, mboxes[i]->name)) - return mboxes[i]; + if (mbox->msg_sender_cb && arg) { + ret = mbox->msg_sender_cb(arg); + if (ret) + goto out; } - return ERR_PTR(-ENOENT); + mbox_seq_toggle(mbox, &msg); + mbox_fifo_write(mbox, msg); + out: + mutex_unlock(&msg_send_lock); + + return 0; } +EXPORT_SYMBOL(omap_mbox_msg_send); -#if defined(CONFIG_ARCH_OMAP1) -static __inline__ int mbsync_irq_save(struct mbox *mbox, unsigned long *flags, - int try_cnt) +/* + * Message receiver(workqueue) + */ +static void mbox_msg_receiver(void *p) { - int cnt; - - local_irq_save(*flags); - if (mbox_is_notfull(mbox)) - 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 (mbox_is_notfull(mbox)) /* success! */ - return 0; - local_irq_restore(*flags); - } + struct omap_mbox *mbox = (struct omap_mbox *)p; + struct omap_mbq *mbq = mbox->mbq; + mbox_msg_t msg; - /* fail! */ - return -1; -} -#elif defined(CONFIG_ARCH_OMAP2) -static __inline__ int mbsync_irq_save(struct mbox *mbox, unsigned long *flags) -{ - long current_state; - DECLARE_WAITQUEUE(wait, current); + while (!mbq_empty(mbq)) { + msg = mbq_get(mbq); + enable_mbox_irq(mbox, IRQ_RX); - do { - local_irq_save(*flags); - if (mbox_is_notfull(mbox)) - return 0; + if (unlikely(mbox_seq_test(mbox, msg))) { + printk(KERN_ERR + "mbox: illegal seq bit! ignoring this command. " + "(%08x)\n", msg); + continue; + } - /* - * mailbox is busy. - */ - local_irq_restore(*flags); - enable_notfull_irq(mbox); - - /* wait until the FIFO becomes not-full */ - add_wait_queue(&mbox->full_wait_q, &wait); - current_state = current->state; - set_current_state(TASK_INTERRUPTIBLE); - if (!mbox_is_notfull(mbox)) /* last check */ - schedule(); - set_current_state(current_state); - remove_wait_queue(&mbox->full_wait_q, &wait); - - if (signal_pending(current)) - return -1; - } while (1); + if (likely(mbox->msg_receive_cb)) + mbox->msg_receive_cb(msg); + } } -#endif /* - * message dispatcher API + * Mailbox interrupt handler */ -int mbox_send(struct mbox *mbox, mbox_msg_t msg) +static irqreturn_t mbox_interrupt(int irq, void *p, struct pt_regs *regs) { - unsigned long flags; + mbox_msg_t msg; + struct omap_mbox *mbox = (struct omap_mbox *)p; -#if defined(CONFIG_ARCH_OMAP1) - /* - * DSP mailbox interrupt latency must be less than 1ms. - */ - if (mbsync_irq_save(mbox, &flags, 1000) < 0) { - printk(KERN_ERR - "mailbox(%s) is busy. message 0x%08x is aborting.\n", - mbox->name, msg); - return -1; + if (is_mbox_irq(mbox, IRQ_TX)) { + disable_mbox_irq(mbox, IRQ_TX); + /* + * 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. + */ + ack_mbox_irq(mbox, IRQ_TX); + wake_up_interruptible_all(&mbox->tx_waitq); } -#elif defined(CONFIG_ARCH_OMAP2) - if (mbsync_irq_save(mbox, &flags) < 0) - return -1; -#endif -#ifdef MBOX_USE_SEQ_BIT - /* add seq_snd to msg */ - msg = (msg & 0x7fffffff) | mbox->seq_snd; - /* flip seq_snd */ - mbox->seq_snd ^= 1 << 31; -#endif + if (!is_mbox_irq(mbox, IRQ_RX)) + return IRQ_HANDLED; - write_mbox(mbox, msg); + while (!mbox_fifo_empty(mbox)) { + msg = mbox_fifo_read(mbox); + if (mbq_add(mbox->mbq, msg)) { /* mbq full */ + disable_mbox_irq(mbox, IRQ_RX); + goto flush_queue; + } + if (mbox->ops->type == OMAP_MBOX_TYPE1) + break; + } - local_irq_restore(flags); - return 0; + /* no more messages in the fifo. clear IRQ source. */ + ack_mbox_irq(mbox, IRQ_RX); + flush_queue: + schedule_work(&mbox->msg_receive); + + return IRQ_HANDLED; } /* - * register / unregister API + * sysfs files */ -int register_mbox_receiver(struct mbox *mbox, unsigned char cmd, - mbox_receiver_t *rcv) +static ssize_t mbox_attr_write(struct class_device *dev, const char *buf, + size_t count) { - if (cmd >= MBOX_CMD_MAX) { - printk(KERN_ERR "register_mbox_receiver(): " - "bad cmd (0x%x)\n", cmd); - return -EINVAL; - } - if (mbox->receiver_map[cmd] != NULL) { - printk(KERN_ERR "register_mbox_receiver(): cmd 0x%x is " - "already reserved.\n", cmd); - return -EINVAL; - } + int ret; + mbox_msg_t msg; + struct omap_mbox *mbox = class_get_devdata(dev); - mbox->receiver_map[cmd] = rcv; - return 0; -} + msg = (mbox_msg_t) simple_strtoul(buf, NULL, 16); -int unregister_mbox_receiver(struct mbox *mbox, unsigned char cmd, - mbox_receiver_t *rcv) -{ - if (cmd >= MBOX_CMD_MAX) { - printk(KERN_ERR "unregister_mbox_receiver(): " - "bad cmd (0x%x)\n", cmd); - return -EINVAL; - } - if (mbox->receiver_map[cmd] != rcv) { - printk(KERN_ERR "unregister_mbox_receiver(): cmd 0x%x and " - "receiver function mismatch!\n", cmd); - return -EINVAL; - } + ret = omap_mbox_msg_send(mbox, msg, NULL); + if (ret) + return -1; - mbox->receiver_map[cmd] = NULL; - return 0; + return count; } -/* - * IRQ disable / enable API - */ -void disable_mbox_irq(struct mbox *mbox) +static ssize_t mbox_attr_read(struct class_device *dev, char *buf) { - disable_irq(mbox->irq); + struct omap_mbox *mbox = class_get_devdata(dev); + + return sprintf(buf, mbox->name); } -void enable_mbox_irq(struct mbox *mbox) +static CLASS_DEVICE_ATTR(mbox, S_IALLUGO, mbox_attr_read, mbox_attr_write); + +static ssize_t mbox_show(struct class *class, char *buf) { - enable_irq(mbox->irq); + return sprintf(buf, "mbox"); } -/* - * init_seq API - */ -void mbox_init_seq(struct mbox *mbox) -{ -#ifdef MBOX_USE_SEQ_BIT - /* backward compatibility */ - mbox->seq_snd = 0x80000000; +static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL); - /* any value other than 0 and 1 << 31 */ - mbox->seq_rcv = 0xffffffff; -#endif /* MBOX_USE_SEQ_BIT */ -} +static struct class omap_mbox_class = { + .name = "mbox", +}; -/* - * receiver workqueue - */ -static void do_mbox(void *p) +static int omap_mbox_init(struct omap_mbox *mbox) { - int empty = 0; - struct mbox *mbox = (struct mbox *)p; - struct mbq *mbq = &mbox->mbq; - mbox_receiver_t *receiver; - mbox_msg_t msg; -#ifdef MBOX_USE_SEQ_BIT - mbox_msg_t seq; -#endif + int ret; - disable_newmsg_irq(mbox); - if ((mbq->rp == mbq->wp) && !mbq->full) - empty = 1; - enable_newmsg_irq(mbox); + if (likely(mbox->ops->startup)) { + ret = mbox->ops->startup(mbox); + if (unlikely(ret)) + return ret; + } - while (!empty) { - msg = mbq->msg[mbq->rp]; -#ifdef MBOX_USE_SEQ_BIT - seq = msg & (1 << 31); + mbox->class_dev.class = &omap_mbox_class; + strlcpy(mbox->class_dev.class_id, mbox->name, KOBJ_NAME_LEN); + class_set_devdata(&mbox->class_dev, mbox); - if (seq == mbox->seq_rcv) { - printk(KERN_ERR - "mbox: illegal seq bit! ignoring this command. " - "(%08x)\n", msg); - goto inc; - } - mbox->seq_rcv = seq; -#endif + ret = class_device_register(&mbox->class_dev); + if (unlikely(ret)) + return ret; - /* call receiver function */ - if ((receiver = mbox->receiver_map[(msg >> 24) & 0x7f]) == NULL) - printk(KERN_ERR - "mbox: unknown message (%08x) received from " - "%s.\n", msg, mbox->name); - else - receiver(msg); - -#ifdef MBOX_USE_SEQ_BIT -inc: -#endif - disable_newmsg_irq(mbox); - 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(mbox); - } - enable_newmsg_irq(mbox); - } -} + class_device_create_file(&mbox->class_dev, &class_device_attr_mbox); -/* - * interrupt handler - */ -static irqreturn_t mbox_int_newmsg(int irq, void *p, struct pt_regs *regs) -{ - struct mbox *mbox = container_of(p, struct mbox, irq_devid_newmsg); - struct mbq *mbq = &mbox->mbq; - mbox_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(mbox)) - return IRQ_NONE; -#endif - - do { -#ifdef CONFIG_ARCH_OMAP2 - if (mbox_nomsg(mbox)) { - /* no more messages in the fifo. clear IRQ source. */ - clear_newmsg_irq(mbox); - break; - } -#endif + ret = request_irq(mbox->irq, mbox_interrupt, SA_INTERRUPT, + mbox->name, mbox); + if (unlikely(ret)) { + printk(KERN_ERR + "failed to register mailbox interrupt:%d\n", ret); + goto fail1; + } + enable_mbox_irq(mbox, IRQ_RX); - msg = &mbq->msg[mbq->wp]; - read_mbox(mbox, msg); + spin_lock_init(&mbox->lock); + INIT_WORK(&mbox->msg_receive, mbox_msg_receiver, mbox); + init_waitqueue_head(&mbox->tx_waitq); - mbq_inc(mbq->wp); - if (mbq->wp == mbq->rp) { /* mbq is full */ - mbq->full = 1; - disable_newmsg_irq(mbox); - break; - } -#if defined(CONFIG_ARCH_OMAP1) - } while (0); /* do it once */ -#elif defined(CONFIG_ARCH_OMAP2) - } while (1); -#endif + ret = mbq_init(&mbox->mbq); + if (unlikely(ret)) + goto fail2; - schedule_work(&mbox->work); - return IRQ_HANDLED; + return 0; + fail2: + free_irq(mbox->irq, mbox); + class_remove_file(&omap_mbox_class, &class_attr_mbox); + class_unregister(&omap_mbox_class); + fail1: + if (unlikely(mbox->ops->shutdown)) + mbox->ops->shutdown(mbox); + + return ret; } -#ifdef CONFIG_ARCH_OMAP2 -static irqreturn_t mbox_int_notfull(int irq, void *p, struct pt_regs *regs) +static void omap_mbox_shutdown(struct omap_mbox *mbox) { - struct mbox *mbox = container_of(p, struct mbox, irq_devid_notfull); - - /* - * mailbox IRQ can be muxed. - * if it is not a notfull interrupt, we do nothing. - */ -#if 0 - if (!has_notfull_irq(mbox)) -#else - if (!(has_notfull_irq(mbox) && notfull_irq_enabled(mbox))) -#endif - return IRQ_NONE; - - disable_notfull_irq(mbox); - -#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(mbox); -#endif - - wake_up_interruptible_all(&mbox->full_wait_q); - return IRQ_HANDLED; + free_irq(mbox->irq, mbox); + class_remove_file(&omap_mbox_class, &class_attr_mbox); + class_unregister(&omap_mbox_class); + + if (unlikely(mbox->ops->shutdown)) + mbox->ops->shutdown(mbox); } -#endif /* CONFIG_ARCH_OMAP2 */ -static int __init mbox_request_irq(struct mbox *mbox, const char *devname) +int omap_mbox_register(struct omap_mbox *mbox) { - int ret; + int ret = 0; + struct omap_mbox **tmp; -#ifdef CONFIG_ARCH_OMAP2 - enable_newmsg_irq(mbox); -#endif + if (!mbox) + return -EINVAL; + if (mbox->next) + return -EBUSY; - ret = request_irq(mbox->irq, mbox_int_newmsg, SA_INTERRUPT | SA_SHIRQ, - devname, &mbox->irq_devid_newmsg); - if (ret) { - printk(KERN_ERR - "failed to register DSP mailbox newmsg interrupt: " - "%d\n", ret); + ret = omap_mbox_init(mbox); + if (ret) return ret; - } -#ifdef CONFIG_ARCH_OMAP2 - ret = request_irq(mbox->irq, mbox_int_notfull, SA_INTERRUPT | SA_SHIRQ, - devname, &mbox->irq_devid_notfull); - if (ret) { - printk(KERN_ERR - "failed to register DSP mailbox notfull interrupt: " - "%d\n", ret); - return ret; + write_lock(&mboxes_lock); + tmp = find_mboxes(mbox->name); + if (*tmp) + ret = -EBUSY; + else + *tmp = mbox; + write_unlock(&mboxes_lock); + + return ret; +} +EXPORT_SYMBOL(omap_mbox_register); + +int omap_mbox_unregister(struct omap_mbox *mbox) +{ + struct omap_mbox **tmp; + + write_lock(&mboxes_lock); + tmp = &mboxes; + while (*tmp) { + if (mbox == *tmp) { + *tmp = mbox->next; + mbox->next = NULL; + write_unlock(&mboxes_lock); + + omap_mbox_shutdown(mbox); + + return 0; + } + tmp = &(*tmp)->next; } -#endif + write_unlock(&mboxes_lock); - return 0; + return -EINVAL; } +EXPORT_SYMBOL(omap_mbox_unregister); -static int __init omap_mailbox_init(void) +static int __init omap_mbox_class_init(void) { - int ret; -#ifdef CONFIG_ARCH_OMAP2 - struct clk *mbox_ick_handle; -#endif - - printk(KERN_INFO "Initializing OMAP Mailboxes\n"); -#ifdef CONFIG_ARCH_OMAP2 - /* - * FIXME: mbox_ick will never unsed - */ - mbox_ick_handle = clk_get(NULL, "mailboxes_ick"); - if (IS_ERR(mbox_ick_handle)) { - printk("Could not get mailboxes_ick\n"); - return -ENODEV; - } else - clk_enable(mbox_ick_handle); -#endif - - if ((ret = mbox_request_irq(&mbox_dsp, "mbox_dsp")) != 0) - return ret; -#ifdef CONFIG_ARCH_OMAP2 - if ((ret = mbox_request_irq(&mbox_iva, "mbox_iva")) != 0) - return ret; -#endif + int ret = class_register(&omap_mbox_class); + if (!ret) + ret = class_create_file(&omap_mbox_class, &class_attr_mbox); - return 0; + return ret; } -arch_initcall(omap_mailbox_init); +static void __exit omap_mbox_class_exit(void) +{ + class_remove_file(&omap_mbox_class, &class_attr_mbox); + class_unregister(&omap_mbox_class); +} -EXPORT_SYMBOL(mbox_get); -EXPORT_SYMBOL(mbox_send); -EXPORT_SYMBOL(register_mbox_receiver); -EXPORT_SYMBOL(unregister_mbox_receiver); -EXPORT_SYMBOL(disable_mbox_irq); -EXPORT_SYMBOL(enable_mbox_irq); -EXPORT_SYMBOL(mbox_init_seq); +subsys_initcall(omap_mbox_class_init); +module_exit(omap_mbox_class_exit); diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h new file mode 100644 index 00000000000..f8b87a18960 --- /dev/null +++ b/arch/arm/plat-omap/mailbox.h @@ -0,0 +1,197 @@ +/* + * Mailbox internal functions + * + * Copyright (C) 2006 Nokia Corporation + * Written by: Hiroshi DOYU + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __ARCH_ARM_PLAT_MAILBOX_H +#define __ARCH_ARM_PLAT_MAILBOX_H + +/* + * Mailbox queue handling API + */ + +#define MBQ_DEPTH 16 +struct omap_mbq { + rwlock_t lock; + mbox_msg_t msg[MBQ_DEPTH]; + mbox_msg_t *rp, *wp; +}; + +static inline int mbq_init(struct omap_mbq **addr) +{ + struct omap_mbq *m = kmalloc(sizeof(struct omap_mbq), GFP_KERNEL); + if (!m) + return -ENOMEM; + + rwlock_init(&m->lock); + + write_lock_irq(&m->lock); + m->rp = m->wp = &m->msg[0]; + write_unlock_irq(&m->lock); + + *addr = m; + + return 0; +} + +static inline int mbq_empty(struct omap_mbq *mbq) +{ + int ret; + + read_lock_irq(&mbq->lock); + ret = (mbq->rp == mbq->wp); + read_unlock_irq(&mbq->lock); + + return ret; +} + +static inline int mbq_full(struct omap_mbq *mbq) +{ + int ret; + mbox_msg_t *p; + + read_lock_irq(&mbq->lock); + p = mbq->wp; + + if (++p == &mbq->msg[MBQ_DEPTH]) + p = &mbq->msg[0]; + + ret = (p == mbq->rp); + + read_unlock_irq(&mbq->lock); + + return ret; +} + +static inline int mbq_add(struct omap_mbq *mbq, mbox_msg_t msg) +{ + int ret = 0; + + write_lock_irq(&mbq->lock); + + *mbq->wp = msg; + if (++mbq->wp == &mbq->msg[MBQ_DEPTH]) + mbq->wp = &mbq->msg[0]; + + if (mbq->wp == mbq->rp) /* full */ + ret = -1;; + + write_unlock_irq(&mbq->lock); + + return ret; +} + +static inline mbox_msg_t mbq_get(struct omap_mbq *mbq) +{ + mbox_msg_t msg; + + write_lock_irq(&mbq->lock); + + msg = *mbq->rp; + + if (++mbq->rp == &mbq->msg[MBQ_DEPTH]) + mbq->rp = &mbq->msg[0]; + + write_unlock_irq(&mbq->lock); + + return msg; +} + +static inline void mbq_exit(struct omap_mbq **addr) +{ + if (*addr) + kfree(*addr); +} + +/* + * Mailbox sequence bit API + */ +#if defined(CONFIG_ARCH_OMAP1) +# define MBOX_USE_SEQ_BIT +#elif defined(CONFIG_ARCH_OMAP2) +# define MBOX_USE_SEQ_BIT +#endif + +#ifdef MBOX_USE_SEQ_BIT +/* seq_rcv should be initialized with any value other than + * 0 and 1 << 31, to allow either value for the first + * message. */ +static inline void mbox_seq_init(struct omap_mbox *mbox) +{ + /* any value other than 0 and 1 << 31 */ + mbox->seq_rcv = 0xffffffff; +} + +static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) +{ + /* add seq_snd to msg */ + *msg = (*msg & 0x7fffffff) | mbox->seq_snd; + /* flip seq_snd */ + mbox->seq_snd ^= 1 << 31; +} + +static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox_msg_t seq = msg & (1 << 31); + if (seq == mbox->seq_rcv) + return -1; + mbox->seq_rcv = seq; + return 0; +} +#else +static inline void mbox_seq_init(struct omap_mbox *mbox) +{ +} +static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) +{ +} +static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) +{ + return 0; +} +#endif + +/* Mailbox FIFO handle functions */ +static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_read(mbox); +} +static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox->ops->fifo_write(mbox, msg); +} +static inline int mbox_fifo_empty(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_empty(mbox); +} +static inline int mbox_fifo_full(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_full(mbox); +} + +/* Mailbox IRQ handle functions */ +static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->enable_irq(mbox, irq); +} +static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->disable_irq(mbox, irq); +} +static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (mbox->ops->ack_irq) + mbox->ops->ack_irq(mbox, irq); +} +static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + return mbox->ops->is_irq(mbox, irq); +} + +#endif /* __ARCH_ARM_PLAT_MAILBOX_H */ diff --git a/arch/arm/plat-omap/mailbox_hw.h b/arch/arm/plat-omap/mailbox_hw.h deleted file mode 100644 index e77012c8dd9..00000000000 --- a/arch/arm/plat-omap/mailbox_hw.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 */ -- 2.41.1