From: Loic Pallardy <loic.palla...@st.com>

Add STEriccson DBX500 PRCM mailbox support.

Signed-off-by: Loic Pallardy <loic.palla...@st.com>
Signed-off-by: Linus Walleij <linus.wall...@linaro.org>
---
 .../devicetree/bindings/mailbox/dbx500-mailbox.txt |  27 +
 drivers/mailbox/Kconfig                            |   7 +
 drivers/mailbox/Makefile                           |   1 +
 drivers/mailbox/mailbox-dbx500.c                   | 648 +++++++++++++++++++++
 include/linux/platform_data/mailbox-dbx500.h       |  12 +
 5 files changed, 695 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/dbx500-mailbox.txt
 create mode 100644 drivers/mailbox/mailbox-dbx500.c
 create mode 100644 include/linux/platform_data/mailbox-dbx500.h

diff --git a/Documentation/devicetree/bindings/mailbox/dbx500-mailbox.txt 
b/Documentation/devicetree/bindings/mailbox/dbx500-mailbox.txt
new file mode 100644
index 0000000..df0f594
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/dbx500-mailbox.txt
@@ -0,0 +1,27 @@
+ST-Ericsson DBx500 PRCM Mailbox Driver
+
+Required properties:
+- compatible           : Should be
+                         "stericsson,db8500-mailbox" for db8500 and db9500
+                         "stericsson,db9540-mailbox" for db9540
+- reg                  : Physical base address and length of mailbox's
+                         registers and shared memory
+- reg-names            : Should contain the reg names "prcm-reg" and
+                         "prcmu-tcdm"
+- interrupts           : contains the IRQ line for the PRCM mailbox
+- interrupt-names      : Should contain the interrupt name "irq"
+- legacy-offset                : Memory offset in shared mem for legacy 
mailboxes
+
+Optional properties:
+- upap-offset          : Memory offset in shared mem for upap mailboxes
+
+Examples:
+
+mailbox {
+       compatible = "stericsson,db8500-mailbox";
+       reg = <0x80157000 0x1000>, <0x801B8000 0x2000>;
+       reg-names = "prcm-reg", "prcmu-tcdm";
+       interrupts = <0 47 0x4>;
+       interrupt-names = "irq";
+       legacy-offset = <0xdd4>;
+};
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index d7692a7..438ea21 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -33,6 +33,12 @@ config OMAP2PLUS_MBOX
          OMAP2/3; or IPU, IVA HD and DSP in OMAP4. Say Y here if you want
          to use OMAP2+ Mailbox framework support.
 
+config DBX500_MBOX
+       tristate "DBx500 Mailbox driver support"
+       depends on ARCH_U8500
+       help
+         Say Y here if you want to use DBx500 Mailbox driver support for
+         power coprocessor access on Ux500 and Ux540 families
 
 config MBOX_KFIFO_SIZE
        int "Mailbox kfifo default buffer size (bytes)"
@@ -44,6 +50,7 @@ config MBOX_KFIFO_SIZE
 
 config MBOX_DATA_SIZE
        int "Mailbox associated data max size (bytes)"
+       default 64 if DBX500_MBOX
        default 4
        help
          Specify the default size of mailbox's associated data buffer
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 9ee0fcb..ee5fb1e 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_PL320_MBOX)        += pl320-ipc.o
 obj-$(CONFIG_MAILBOX)          += mailbox.o
 obj-$(CONFIG_OMAP1_MBOX)       += mailbox-omap1.o
 obj-$(CONFIG_OMAP2PLUS_MBOX)   += mailbox-omap2.o
+obj-$(CONFIG_DBX500_MBOX)      += mailbox-dbx500.o
diff --git a/drivers/mailbox/mailbox-dbx500.c b/drivers/mailbox/mailbox-dbx500.c
new file mode 100644
index 0000000..e9d2b0a
--- /dev/null
+++ b/drivers/mailbox/mailbox-dbx500.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Loic Pallardy <loic.palla...@st.com> for ST-Ericsson
+ * DBX500 PRCM Mailbox driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_data/mailbox-dbx500.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irqdomain.h>
+
+#include "mailbox_internal.h"
+
+#define MAILBOX_LEGACY         0
+#define MAILBOX_UPAP           1
+
+enum {
+       MAILBOX_BLOCKING,
+       MAILBOX_ATOMIC,
+};
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL      0x0fc
+#define PRCM_MBOX_CPU_SET      0x100
+#define PRCM_MBOX_CPU_CLR      0x104
+
+#define PRCM_ARM_IT1_CLR       0x48C
+#define PRCM_ARM_IT1_VAL       0x494
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/* CPU mailbox shared memory */
+#define PRCM_MBOX_LEGACY_SIZE          0x220
+#define _PRCM_MBOX_HEADER              0x214 /* 16 bytes */
+#define PRCM_MBOX_HEADER_REQ_MB0       (_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_REQ_MB1       (_PRCM_MBOX_HEADER + 0x1)
+#define PRCM_MBOX_HEADER_REQ_MB2       (_PRCM_MBOX_HEADER + 0x2)
+#define PRCM_MBOX_HEADER_REQ_MB3       (_PRCM_MBOX_HEADER + 0x3)
+#define PRCM_MBOX_HEADER_REQ_MB4       (_PRCM_MBOX_HEADER + 0x4)
+#define PRCM_MBOX_HEADER_REQ_MB5       (_PRCM_MBOX_HEADER + 0x5)
+#define PRCM_MBOX_HEADER_ACK_MB0       (_PRCM_MBOX_HEADER + 0x8)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0                   0x208 /* 12 bytes  */
+#define PRCM_REQ_MB1                   0x1FC /* 12 bytes  */
+#define PRCM_REQ_MB2                   0x1EC /* 16 bytes  */
+#define PRCM_REQ_MB3                   0x78  /* 372 bytes  */
+#define PRCM_REQ_MB4                   0x74  /* 4 bytes  */
+#define PRCM_REQ_MB5                   0x70  /* 4 bytes  */
+#define PRCM_REQ_PASR                  0x30 /* 4 bytes */
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0                   0x34 /* 52 bytes  */
+#define PRCM_ACK_MB1                   0x30 /* 4 bytes */
+#define PRCM_ACK_MB2                   0x2C /* 4 bytes */
+#define PRCM_ACK_MB3                   0x28 /* 4 bytes */
+#define PRCM_ACK_MB4                   0x24 /* 4 bytes */
+#define PRCM_ACK_MB5                   0x20 /* 4 bytes */
+
+/* Ack Mailboxe sizes */
+#define PRCM_ACK_MB0_SIZE              0x24 /* 52 bytes  */
+#define PRCM_ACK_MB1_SIZE              0x4 /* 4 bytes */
+#define PRCM_ACK_MB2_SIZE              0x1 /* 1 bytes */
+#define PRCM_ACK_MB3_SIZE              0x2 /* 2 bytes */
+#define PRCM_ACK_MB4_SIZE              0x0 /* 0 bytes */
+#define PRCM_ACK_MB5_SIZE              0x4 /* 4 bytes */
+
+static void __iomem *mbox_base;
+static void __iomem *tcdm_mem_base;
+
+static u8 prcm_mbox_irq_mask; /* masked by default */
+static DEFINE_SPINLOCK(prcm_mbox_irqs_lock);
+
+struct dbx500_mbox_priv {
+       int                     access_mode;
+       int                     type;
+       int                     header_size;
+       unsigned int            tx_header_offset;
+       unsigned int            rx_header_offset;
+       unsigned int            tx_offset;
+       unsigned int            rx_offset;
+       unsigned int            rx_size;
+       unsigned int            sw_irq;
+       bool                    empty_flag;
+};
+
+static inline unsigned int mbox_read_reg(size_t ofs)
+{
+       return __raw_readl(mbox_base + ofs);
+}
+
+static inline void mbox_write_reg(u32 val, size_t ofs)
+{
+       __raw_writel(val, mbox_base + ofs);
+}
+
+/* Mailbox H/W preparations */
+static struct irq_chip dbx500_mbox_irq_chip;
+static struct irq_domain *dbx500_mbox_irq_domain;
+
+static int dbx500_mbox_startup(struct mailbox *mbox)
+{
+       /* Nothing to do */
+       return 0;
+}
+
+/* Mailbox IRQ handle functions */
+
+static void dbx500_mbox_enable_irq(struct mailbox *mbox, mailbox_irq_t irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&prcm_mbox_irqs_lock, flags);
+
+       prcm_mbox_irq_mask |= MBOX_BIT(mbox->id);
+
+       spin_unlock_irqrestore(&prcm_mbox_irqs_lock, flags);
+
+}
+
+static void dbx500_mbox_disable_irq(struct mailbox *mbox, mailbox_irq_t irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&prcm_mbox_irqs_lock, flags);
+
+       prcm_mbox_irq_mask &= ~MBOX_BIT(mbox->id);
+
+       spin_unlock_irqrestore(&prcm_mbox_irqs_lock, flags);
+
+}
+
+static void dbx500_mbox_ack_irq(struct mailbox *mbox, mailbox_irq_t irq)
+{
+       if (irq == IRQ_RX)
+               mbox_write_reg(MBOX_BIT(mbox->id), PRCM_ARM_IT1_CLR);
+}
+
+static int dbx500_mbox_is_irq(struct mailbox *mbox, mailbox_irq_t irq)
+{
+       struct dbx500_mbox_priv *priv = (struct dbx500_mbox_priv *)mbox->priv;
+
+       if (irq == IRQ_RX) {
+               if (mbox_read_reg(PRCM_ARM_IT1_VAL) & MBOX_BIT(mbox->id)) {
+                       priv->empty_flag = true;
+                       return 1;
+               } else {
+                       return 0;
+               }
+       } else {
+               return 0;
+       }
+}
+
+/* message management */
+
+static int dbx500_mbox_is_ready(struct mailbox *mbox)
+{
+       return mbox_read_reg(PRCM_MBOX_CPU_VAL) & MBOX_BIT(mbox->id);
+}
+
+static int dbx500_mbox_write(struct mailbox *mbox,
+               struct mailbox_msg *msg)
+{
+       int j;
+       struct dbx500_mbox_priv *priv = (struct dbx500_mbox_priv *)mbox->priv;
+
+       if (msg->size && !msg->pdata)
+               return -EINVAL;
+
+       while (dbx500_mbox_is_ready(mbox))
+               cpu_relax();
+
+       /* write header */
+       if (priv->header_size)
+               writeb(msg->header, tcdm_mem_base + priv->tx_header_offset);
+
+       /* write data */
+       for (j = 0; j < msg->size; j++)
+               writeb(((unsigned char *)msg->pdata)[j],
+                               tcdm_mem_base + priv->tx_offset + j);
+
+       /* send event */
+       mbox_write_reg(MBOX_BIT(mbox->id), PRCM_MBOX_CPU_SET);
+
+       return 0;
+}
+
+static void dbx500_mbox_read(struct mailbox *mbox, struct mailbox_msg *msg)
+{
+       struct dbx500_mbox_priv *priv = (struct dbx500_mbox_priv *)mbox->priv;
+
+       msg->header = readb(tcdm_mem_base + priv->rx_header_offset);
+       msg->pdata = (unsigned char *)(tcdm_mem_base + priv->rx_offset);
+
+       msg->size = priv->rx_size;
+       priv->empty_flag = false;
+}
+
+static int dbx500_mbox_empty(struct mailbox *mbox)
+{
+       struct dbx500_mbox_priv *priv = (struct dbx500_mbox_priv *)mbox->priv;
+       if (priv->empty_flag)
+               return 0;
+       else
+               return 1;
+}
+
+static int dbx500_mbox_poll_for_space(struct mailbox *mbox)
+{
+       return 0;
+}
+/*  interrupt management */
+
+/*  mask/unmask must be managed by SW */
+
+static void mbox_irq_mask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&prcm_mbox_irqs_lock, flags);
+
+       prcm_mbox_irq_mask &= ~MBOX_BIT(d->hwirq);
+
+       spin_unlock_irqrestore(&prcm_mbox_irqs_lock, flags);
+}
+
+static void mbox_irq_unmask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&prcm_mbox_irqs_lock, flags);
+
+       prcm_mbox_irq_mask |= MBOX_BIT(d->hwirq);
+
+       spin_unlock_irqrestore(&prcm_mbox_irqs_lock, flags);
+}
+
+static void mbox_irq_ack(struct irq_data *d)
+{
+       mbox_write_reg(MBOX_BIT(d->hwirq), PRCM_ARM_IT1_CLR);
+}
+
+static struct irq_chip dbx500_mbox_irq_chip = {
+       .name           = "dbx500_mbox",
+       .irq_disable    = mbox_irq_unmask,
+       .irq_ack        = mbox_irq_ack,
+       .irq_mask       = mbox_irq_mask,
+       .irq_unmask     = mbox_irq_unmask,
+};
+
+static int dbx500_mbox_irq_map(struct irq_domain *d, unsigned int irq,
+                              irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &dbx500_mbox_irq_chip,
+                               handle_simple_irq);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops dbx500_mbox_irq_ops = {
+       .map    = dbx500_mbox_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static irqreturn_t dbx500_mbox_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+
+       bits = (mbox_read_reg(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       bits &= prcm_mbox_irq_mask;
+
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       generic_handle_irq(
+                               irq_find_mapping(dbx500_mbox_irq_domain, n));
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/* 5 mailboxes AP <--> PRCMU */
+static struct mailbox_ops dbx500_mbox_ops = {
+       .type           = MBOX_SHARED_MEM_TYPE,
+       .startup        = dbx500_mbox_startup,
+       .enable_irq     = dbx500_mbox_enable_irq,
+       .disable_irq    = dbx500_mbox_disable_irq,
+       .ack_irq        = dbx500_mbox_ack_irq,
+       .is_irq         = dbx500_mbox_is_irq,
+       .read           = dbx500_mbox_read,
+       .write          = dbx500_mbox_write,
+       .empty          = dbx500_mbox_empty,
+       .poll_for_space = dbx500_mbox_poll_for_space,
+};
+
+struct dbx500_mbox_priv mbox0_priv = {
+       .access_mode            = MAILBOX_ATOMIC,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB0,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB0,
+       .rx_header_offset       = PRCM_MBOX_HEADER_ACK_MB0,
+       .rx_offset              = PRCM_ACK_MB0,
+       .rx_size                = PRCM_ACK_MB0_SIZE,
+};
+
+struct mailbox mbox0_info = {
+       .name   = "mbox0",
+       .id     = 0,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox0_priv,
+};
+
+struct dbx500_mbox_priv mbox1_priv = {
+       .access_mode            = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB1,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB1,
+       .rx_header_offset       = PRCM_MBOX_HEADER_REQ_MB1,
+       .rx_offset              = PRCM_ACK_MB1,
+       .rx_size                = PRCM_ACK_MB1_SIZE,
+};
+
+struct mailbox mbox1_info = {
+       .name   = "mbox1",
+       .id     = 1,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox1_priv,
+};
+
+struct dbx500_mbox_priv mbox2_priv = {
+       .access_mode            = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB2,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB2,
+       .rx_header_offset       = PRCM_MBOX_HEADER_REQ_MB2,
+       .rx_offset              = PRCM_ACK_MB2,
+       .rx_size                = PRCM_ACK_MB2_SIZE,
+};
+
+struct mailbox mbox2_info = {
+       .name   = "mbox2",
+       .id     = 2,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox2_priv,
+};
+
+struct dbx500_mbox_priv mbox3_priv = {
+       .access_mode            = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB3,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB3,
+       .rx_header_offset       = PRCM_MBOX_HEADER_REQ_MB3,
+       .rx_offset              = PRCM_ACK_MB3,
+       .rx_size                = PRCM_ACK_MB3_SIZE,
+};
+
+struct mailbox mbox3_info = {
+       .name   = "mbox3",
+       .id     = 3,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox3_priv,
+};
+
+struct dbx500_mbox_priv mbox4_priv = {
+       .access_mode            = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB4,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB4,
+       .rx_header_offset       = PRCM_MBOX_HEADER_REQ_MB4,
+       .rx_offset              = PRCM_ACK_MB4,
+       .rx_size                = PRCM_ACK_MB4_SIZE,
+};
+
+struct mailbox mbox4_info = {
+       .name   = "mbox4",
+       .id     = 4,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox4_priv,
+};
+
+struct dbx500_mbox_priv mbox5_priv = {
+       .access_mode            = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_LEGACY,
+       .tx_header_offset       = PRCM_MBOX_HEADER_REQ_MB5,
+       .header_size            = 1,
+       .tx_offset              = PRCM_REQ_MB5,
+       .rx_header_offset       = PRCM_MBOX_HEADER_REQ_MB5,
+       .rx_offset              = PRCM_ACK_MB5,
+       .rx_size                = PRCM_ACK_MB5_SIZE,
+};
+
+struct mailbox mbox5_info = {
+       .name   = "mbox5",
+       .id     = 5,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox5_priv,
+};
+
+struct mailbox mbox6_info = {
+       .name   = "mbox6",
+       .id     = 6,
+       .ops    = &dbx500_mbox_ops,
+};
+
+struct mailbox mbox7_info = {
+       .name   = "mbox7",
+       .id     = 7,
+       .ops    = &dbx500_mbox_ops,
+};
+
+/* x540 mailbox definition */
+struct dbx500_mbox_priv mbox1_upap_priv = {
+       .access_mode    = MAILBOX_BLOCKING,
+       .type                   = MAILBOX_UPAP,
+       .tx_header_offset       = 0,
+       .header_size    = 0,
+       .tx_offset      = 0,
+       .rx_offset      = 0, /* TODO to be replaced by dynamic detection */
+       .rx_size        = 0x40,
+};
+
+struct mailbox mbox1_upap_info = {
+       .name   = "mbox1_upap",
+       .id     = 1,
+       .ops    = &dbx500_mbox_ops,
+       .priv   = &mbox1_upap_priv,
+};
+
+struct mailbox *db8500_mboxes[] = { &mbox0_info, &mbox1_info, &mbox2_info,
+       &mbox3_info, &mbox4_info, &mbox5_info, &mbox6_info, &mbox7_info,
+       NULL };
+
+struct mailbox *dbx540_mboxes[] = { &mbox0_info, &mbox2_info,
+       &mbox3_info, &mbox4_info, &mbox5_info, &mbox6_info, &mbox7_info,
+       &mbox1_upap_info, NULL };
+
+static const struct of_device_id dbx500_mailbox_match[] = {
+       { .compatible = "stericsson,db8500-mailbox",
+               .data = (void *)db8500_mboxes,
+       },
+       { .compatible = "stericsson,db9540-mailbox",
+               .data = (void *)dbx540_mboxes,
+       },
+       { /* sentinel */}
+};
+
+static int dbx500_mbox_probe(struct platform_device *pdev)
+{
+       const struct platform_device_id *platid = platform_get_device_id(pdev);
+       struct resource *mem;
+       int ret, i, irq;
+       u32 legacy_offset = 0;
+       u32 upap_offset = 0, upap_size = PRCM_MBOX_LEGACY_SIZE;
+       struct mailbox **list;
+       struct dbx500_plat_data *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
+       bool upap_used = false;
+
+       if (!pdata) {
+               if (np) {
+                       if (of_property_read_u32(np, "legacy-offset",
+                                                       &legacy_offset)) {
+                               /* missing legacy-offset */
+                               dev_err(&pdev->dev, "No legacy offset found\n");
+                               return -ENODEV;
+                       }
+                       if (of_property_read_u32(np, "upap-offset",
+                                                       &upap_offset)) {
+                               dev_dbg(&pdev->dev, "No upap offset found\n");
+                               upap_offset = -1;
+                       }
+                       list = (struct mailbox **)of_match_device(
+                                       dbx500_mailbox_match, &pdev->dev)->data;
+                       if (!list) {
+                               /* No mailbox configuration */
+                               dev_err(&pdev->dev, "No configuration found\n");
+                               return -ENODEV;
+                       }
+               } else {
+                       /* No mailbox configuration */
+                       dev_err(&pdev->dev, "No configuration found\n");
+                       return -ENODEV;
+               }
+       } else {
+               list = (struct mailbox **)platid->driver_data;
+               legacy_offset = pdata->legacy_offset;
+               upap_offset = pdata->upap_offset;
+       }
+
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcm-reg");
+       mbox_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!mbox_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
+       tcdm_mem_base = devm_ioremap(&pdev->dev, mem->start,
+                                                       resource_size(mem));
+       if (!tcdm_mem_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* check mailbox offset values */
+       if (legacy_offset >= (resource_size(mem) - PRCM_MBOX_LEGACY_SIZE)) {
+               dev_err(&pdev->dev, "Incorrect legacy offset value\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; list[i]; i++) {
+               struct mailbox *mbox = list[i];
+               struct dbx500_mbox_priv *priv =
+                       (struct dbx500_mbox_priv *)mbox->priv;
+               if (!priv)
+                       continue;
+               if (priv->type == MAILBOX_UPAP) {
+                       upap_used = true;
+                       upap_size += priv->rx_size;
+                       break;
+               }
+       }
+
+       if (upap_used && (upap_offset >= (resource_size(mem) - upap_size))) {
+               dev_err(&pdev->dev, "Incorrect upap offset value\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       /* clean all mailboxes */
+       mbox_write_reg(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
+       ret = request_irq(irq, dbx500_mbox_irq_handler,
+                       IRQF_NO_SUSPEND, "db8500_mbox", NULL);
+       if (ret) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dbx500_mbox_irq_domain = irq_domain_add_linear(
+               np, NUM_MB, &dbx500_mbox_irq_ops, NULL);
+
+       if (!dbx500_mbox_irq_domain) {
+               dev_err(&pdev->dev, "Failed to create irqdomain\n");
+               ret = -ENOSYS;
+               goto irq_free;
+       }
+
+       /*
+        * Update mailbox shared memory buffer offset according to mailbox
+        * type
+        */
+       for (i = 0; list[i]; i++) {
+               struct mailbox *mbox = list[i];
+               struct dbx500_mbox_priv *priv =
+                       (struct dbx500_mbox_priv *)mbox->priv;
+               if (!priv)
+                       continue;
+               mbox->irq = irq_create_mapping(dbx500_mbox_irq_domain,
+                                                               mbox->id);
+               if (priv->type == MAILBOX_LEGACY) {
+                       priv->rx_offset += legacy_offset;
+                       priv->rx_header_offset += legacy_offset;
+                       priv->tx_offset += legacy_offset;
+                       priv->tx_header_offset += legacy_offset;
+               } else if (priv->type == MAILBOX_UPAP) {
+                       priv->tx_offset += upap_offset;
+                       priv->rx_offset += upap_offset;
+               }
+       }
+
+       ret = mailbox_register(&pdev->dev, list);
+irq_free:
+       if (ret)
+               free_irq(irq, NULL);
+
+out:
+       return ret;
+}
+
+static int dbx500_mbox_remove(struct platform_device *pdev)
+{
+       mailbox_unregister();
+       iounmap(mbox_base);
+       return 0;
+}
+
+static const struct platform_device_id dbx500_mbox_id[] = {
+       {
+               .name = "db8500-mailbox",
+               .driver_data = (unsigned long) db8500_mboxes,
+       }, {
+               .name = "db9540-mailbox",
+               .driver_data = (unsigned long) dbx540_mboxes,
+       }, {
+               /* sentinel */
+       }
+};
+
+static struct platform_driver dbx500_mbox_driver = {
+       .probe = dbx500_mbox_probe,
+       .remove = dbx500_mbox_remove,
+       .driver = {
+               .name = "dbx500-mailbox",
+               .of_match_table = dbx500_mailbox_match,
+       },
+       .id_table = dbx500_mbox_id,
+};
+
+static int __init dbx500_mbox_init(void)
+{
+       return platform_driver_register(&dbx500_mbox_driver);
+}
+
+static void __exit dbx500_mbox_exit(void)
+{
+       platform_driver_unregister(&dbx500_mbox_driver);
+}
+
+postcore_initcall(dbx500_mbox_init);
+module_exit(dbx500_mbox_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ST-Ericsson mailbox: dbx500 architecture specific 
functions");
+MODULE_AUTHOR("Loic Pallardy <loic.palla...@st.com>");
+MODULE_ALIAS("platform:dbx500-mailbox");
diff --git a/include/linux/platform_data/mailbox-dbx500.h 
b/include/linux/platform_data/mailbox-dbx500.h
new file mode 100644
index 0000000..d5aebd9
--- /dev/null
+++ b/include/linux/platform_data/mailbox-dbx500.h
@@ -0,0 +1,12 @@
+/*
+ * mailbox-dbx500.h
+ *
+ * Copyright (C) ST-Ericsson SA 2012
+ * Author:  <loic.palla...@st.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+struct dbx500_plat_data {
+       unsigned int legacy_offset;
+       unsigned int upap_offset;
+};
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to