]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: mailbox restructure
authorHiroshi DOYU <Hiroshi.DOYU@nokia.com>
Thu, 21 Sep 2006 14:41:41 +0000 (17:41 +0300)
committerJuha Yrjola <juha.yrjola@solidboot.com>
Thu, 21 Sep 2006 15:45:51 +0000 (18:45 +0300)
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 <Hiroshi.DOYU@nokia.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
arch/arm/plat-omap/dsp/dsp_core.c
arch/arm/plat-omap/dsp/dsp_mbcmd.h
arch/arm/plat-omap/dsp/dsp_mem.c
arch/arm/plat-omap/mailbox.c
arch/arm/plat-omap/mailbox.h [new file with mode: 0644]
arch/arm/plat-omap/mailbox_hw.h [deleted file]

index b012f39d1985912009e8e651473c5946101ee716..f0b303f9c660e6497653693bd601de0e6a5fc42c 100644 (file)
 #include "dsp_mbcmd.h"
 #include "dsp.h"
 #include "ipbuf.h"
+#include "dsp_common.h"
 
 MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
 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);
index 22b1548c63727f1ed55bdcfc7ca0c9254568dc55..8d4ff05cd815087f21748df354b9b6309de3b34d 100644 (file)
  *
  */
 
+/*
+ * 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
  */
index eaf9caf5e0e0c52c606fc661e542ca8a9cfd3548..4b21c3863857d3ee336ac24bd91b995c7941f0af 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/arch/dsp_common.h>
 #include "uaccess_dsp.h"
 #include "dsp_mbcmd.h"
-#include "../mailbox_hw.h"
 #include "dsp.h"
 #include "ioctl.h"
 #include "ipbuf.h"
index bb3ccd05931415378e19bf4b0fee56d1a73763fd..e8ed9fba738c7ceb87b96e5bc1c18abc443a08fe 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2006 Nokia Corporation. All rights reserved.
  *
  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *             Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/device.h>
 #include <linux/err.h>
-#ifdef CONFIG_ARCH_OMAP2
-#include <linux/clk.h>
-#endif
 #include <asm/io.h>
-#ifdef CONFIG_ARCH_OMAP1
 #include <asm/delay.h>
-#endif
 #include <asm/arch/mailbox.h>
-#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 (file)
index 0000000..f8b87a1
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Mailbox internal functions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * 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 (file)
index e77012c..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Header for OMAP mailbox driver
- *
- * Copyright (C) 2006 Nokia Corporation. All rights reserved.
- *
- * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <asm/hardware.h>
-
-#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 */