linux/arch/arm/mach-omap2/mailbox.c
<<
>>
Prefs
   1/*
   2 * Mailbox reservation modules for OMAP2/3
   3 *
   4 * Copyright (C) 2006-2009 Nokia Corporation
   5 * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
   6 *        and  Paul Mundt
   7 *
   8 * This file is subject to the terms and conditions of the GNU General Public
   9 * License.  See the file "COPYING" in the main directory of this archive
  10 * for more details.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/clk.h>
  15#include <linux/err.h>
  16#include <linux/platform_device.h>
  17#include <linux/io.h>
  18#include <linux/pm_runtime.h>
  19
  20#include <plat/mailbox.h>
  21
  22#include "soc.h"
  23
  24#define MAILBOX_REVISION                0x000
  25#define MAILBOX_MESSAGE(m)              (0x040 + 4 * (m))
  26#define MAILBOX_FIFOSTATUS(m)           (0x080 + 4 * (m))
  27#define MAILBOX_MSGSTATUS(m)            (0x0c0 + 4 * (m))
  28#define MAILBOX_IRQSTATUS(u)            (0x100 + 8 * (u))
  29#define MAILBOX_IRQENABLE(u)            (0x104 + 8 * (u))
  30
  31#define OMAP4_MAILBOX_IRQSTATUS(u)      (0x104 + 0x10 * (u))
  32#define OMAP4_MAILBOX_IRQENABLE(u)      (0x108 + 0x10 * (u))
  33#define OMAP4_MAILBOX_IRQENABLE_CLR(u)  (0x10c + 0x10 * (u))
  34
  35#define MAILBOX_IRQ_NEWMSG(m)           (1 << (2 * (m)))
  36#define MAILBOX_IRQ_NOTFULL(m)          (1 << (2 * (m) + 1))
  37
  38#define MBOX_REG_SIZE                   0x120
  39
  40#define OMAP4_MBOX_REG_SIZE             0x130
  41
  42#define MBOX_NR_REGS                    (MBOX_REG_SIZE / sizeof(u32))
  43#define OMAP4_MBOX_NR_REGS              (OMAP4_MBOX_REG_SIZE / sizeof(u32))
  44
  45static void __iomem *mbox_base;
  46
  47struct omap_mbox2_fifo {
  48        unsigned long msg;
  49        unsigned long fifo_stat;
  50        unsigned long msg_stat;
  51};
  52
  53struct omap_mbox2_priv {
  54        struct omap_mbox2_fifo tx_fifo;
  55        struct omap_mbox2_fifo rx_fifo;
  56        unsigned long irqenable;
  57        unsigned long irqstatus;
  58        u32 newmsg_bit;
  59        u32 notfull_bit;
  60        u32 ctx[OMAP4_MBOX_NR_REGS];
  61        unsigned long irqdisable;
  62};
  63
  64static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
  65                                  omap_mbox_type_t irq);
  66
  67static inline unsigned int mbox_read_reg(size_t ofs)
  68{
  69        return __raw_readl(mbox_base + ofs);
  70}
  71
  72static inline void mbox_write_reg(u32 val, size_t ofs)
  73{
  74        __raw_writel(val, mbox_base + ofs);
  75}
  76
  77/* Mailbox H/W preparations */
  78static int omap2_mbox_startup(struct omap_mbox *mbox)
  79{
  80        u32 l;
  81
  82        pm_runtime_enable(mbox->dev->parent);
  83        pm_runtime_get_sync(mbox->dev->parent);
  84
  85        l = mbox_read_reg(MAILBOX_REVISION);
  86        pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
  87
  88        return 0;
  89}
  90
  91static void omap2_mbox_shutdown(struct omap_mbox *mbox)
  92{
  93        pm_runtime_put_sync(mbox->dev->parent);
  94        pm_runtime_disable(mbox->dev->parent);
  95}
  96
  97/* Mailbox FIFO handle functions */
  98static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
  99{
 100        struct omap_mbox2_fifo *fifo =
 101                &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
 102        return (mbox_msg_t) mbox_read_reg(fifo->msg);
 103}
 104
 105static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
 106{
 107        struct omap_mbox2_fifo *fifo =
 108                &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
 109        mbox_write_reg(msg, fifo->msg);
 110}
 111
 112static int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
 113{
 114        struct omap_mbox2_fifo *fifo =
 115                &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
 116        return (mbox_read_reg(fifo->msg_stat) == 0);
 117}
 118
 119static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
 120{
 121        struct omap_mbox2_fifo *fifo =
 122                &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
 123        return mbox_read_reg(fifo->fifo_stat);
 124}
 125
 126/* Mailbox IRQ handle functions */
 127static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
 128                omap_mbox_type_t irq)
 129{
 130        struct omap_mbox2_priv *p = mbox->priv;
 131        u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 132
 133        l = mbox_read_reg(p->irqenable);
 134        l |= bit;
 135        mbox_write_reg(l, p->irqenable);
 136}
 137
 138static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
 139                omap_mbox_type_t irq)
 140{
 141        struct omap_mbox2_priv *p = mbox->priv;
 142        u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 143
 144        if (!cpu_is_omap44xx())
 145                bit = mbox_read_reg(p->irqdisable) & ~bit;
 146
 147        mbox_write_reg(bit, p->irqdisable);
 148}
 149
 150static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
 151                omap_mbox_type_t irq)
 152{
 153        struct omap_mbox2_priv *p = mbox->priv;
 154        u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 155
 156        mbox_write_reg(bit, p->irqstatus);
 157
 158        /* Flush posted write for irq status to avoid spurious interrupts */
 159        mbox_read_reg(p->irqstatus);
 160}
 161
 162static int omap2_mbox_is_irq(struct omap_mbox *mbox,
 163                omap_mbox_type_t irq)
 164{
 165        struct omap_mbox2_priv *p = mbox->priv;
 166        u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 167        u32 enable = mbox_read_reg(p->irqenable);
 168        u32 status = mbox_read_reg(p->irqstatus);
 169
 170        return (int)(enable & status & bit);
 171}
 172
 173static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
 174{
 175        int i;
 176        struct omap_mbox2_priv *p = mbox->priv;
 177        int nr_regs;
 178        if (cpu_is_omap44xx())
 179                nr_regs = OMAP4_MBOX_NR_REGS;
 180        else
 181                nr_regs = MBOX_NR_REGS;
 182        for (i = 0; i < nr_regs; i++) {
 183                p->ctx[i] = mbox_read_reg(i * sizeof(u32));
 184
 185                dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
 186                        i, p->ctx[i]);
 187        }
 188}
 189
 190static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
 191{
 192        int i;
 193        struct omap_mbox2_priv *p = mbox->priv;
 194        int nr_regs;
 195        if (cpu_is_omap44xx())
 196                nr_regs = OMAP4_MBOX_NR_REGS;
 197        else
 198                nr_regs = MBOX_NR_REGS;
 199        for (i = 0; i < nr_regs; i++) {
 200                mbox_write_reg(p->ctx[i], i * sizeof(u32));
 201
 202                dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
 203                        i, p->ctx[i]);
 204        }
 205}
 206
 207static struct omap_mbox_ops omap2_mbox_ops = {
 208        .type           = OMAP_MBOX_TYPE2,
 209        .startup        = omap2_mbox_startup,
 210        .shutdown       = omap2_mbox_shutdown,
 211        .fifo_read      = omap2_mbox_fifo_read,
 212        .fifo_write     = omap2_mbox_fifo_write,
 213        .fifo_empty     = omap2_mbox_fifo_empty,
 214        .fifo_full      = omap2_mbox_fifo_full,
 215        .enable_irq     = omap2_mbox_enable_irq,
 216        .disable_irq    = omap2_mbox_disable_irq,
 217        .ack_irq        = omap2_mbox_ack_irq,
 218        .is_irq         = omap2_mbox_is_irq,
 219        .save_ctx       = omap2_mbox_save_ctx,
 220        .restore_ctx    = omap2_mbox_restore_ctx,
 221};
 222
 223/*
 224 * MAILBOX 0: ARM -> DSP,
 225 * MAILBOX 1: ARM <- DSP.
 226 * MAILBOX 2: ARM -> IVA,
 227 * MAILBOX 3: ARM <- IVA.
 228 */
 229
 230/* FIXME: the following structs should be filled automatically by the user id */
 231
 232#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2)
 233/* DSP */
 234static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
 235        .tx_fifo = {
 236                .msg            = MAILBOX_MESSAGE(0),
 237                .fifo_stat      = MAILBOX_FIFOSTATUS(0),
 238        },
 239        .rx_fifo = {
 240                .msg            = MAILBOX_MESSAGE(1),
 241                .msg_stat       = MAILBOX_MSGSTATUS(1),
 242        },
 243        .irqenable      = MAILBOX_IRQENABLE(0),
 244        .irqstatus      = MAILBOX_IRQSTATUS(0),
 245        .notfull_bit    = MAILBOX_IRQ_NOTFULL(0),
 246        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(1),
 247        .irqdisable     = MAILBOX_IRQENABLE(0),
 248};
 249
 250struct omap_mbox mbox_dsp_info = {
 251        .name   = "dsp",
 252        .ops    = &omap2_mbox_ops,
 253        .priv   = &omap2_mbox_dsp_priv,
 254};
 255#endif
 256
 257#if defined(CONFIG_ARCH_OMAP3)
 258struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL };
 259#endif
 260
 261#if defined(CONFIG_SOC_OMAP2420)
 262/* IVA */
 263static struct omap_mbox2_priv omap2_mbox_iva_priv = {
 264        .tx_fifo = {
 265                .msg            = MAILBOX_MESSAGE(2),
 266                .fifo_stat      = MAILBOX_FIFOSTATUS(2),
 267        },
 268        .rx_fifo = {
 269                .msg            = MAILBOX_MESSAGE(3),
 270                .msg_stat       = MAILBOX_MSGSTATUS(3),
 271        },
 272        .irqenable      = MAILBOX_IRQENABLE(3),
 273        .irqstatus      = MAILBOX_IRQSTATUS(3),
 274        .notfull_bit    = MAILBOX_IRQ_NOTFULL(2),
 275        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(3),
 276        .irqdisable     = MAILBOX_IRQENABLE(3),
 277};
 278
 279static struct omap_mbox mbox_iva_info = {
 280        .name   = "iva",
 281        .ops    = &omap2_mbox_ops,
 282        .priv   = &omap2_mbox_iva_priv,
 283};
 284#endif
 285
 286#ifdef CONFIG_ARCH_OMAP2
 287struct omap_mbox *omap2_mboxes[] = {
 288        &mbox_dsp_info,
 289#ifdef CONFIG_SOC_OMAP2420
 290        &mbox_iva_info,
 291#endif
 292        NULL
 293};
 294#endif
 295
 296#if defined(CONFIG_ARCH_OMAP4)
 297/* OMAP4 */
 298static struct omap_mbox2_priv omap2_mbox_1_priv = {
 299        .tx_fifo = {
 300                .msg            = MAILBOX_MESSAGE(0),
 301                .fifo_stat      = MAILBOX_FIFOSTATUS(0),
 302        },
 303        .rx_fifo = {
 304                .msg            = MAILBOX_MESSAGE(1),
 305                .msg_stat       = MAILBOX_MSGSTATUS(1),
 306        },
 307        .irqenable      = OMAP4_MAILBOX_IRQENABLE(0),
 308        .irqstatus      = OMAP4_MAILBOX_IRQSTATUS(0),
 309        .notfull_bit    = MAILBOX_IRQ_NOTFULL(0),
 310        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(1),
 311        .irqdisable     = OMAP4_MAILBOX_IRQENABLE_CLR(0),
 312};
 313
 314struct omap_mbox mbox_1_info = {
 315        .name   = "mailbox-1",
 316        .ops    = &omap2_mbox_ops,
 317        .priv   = &omap2_mbox_1_priv,
 318};
 319
 320static struct omap_mbox2_priv omap2_mbox_2_priv = {
 321        .tx_fifo = {
 322                .msg            = MAILBOX_MESSAGE(3),
 323                .fifo_stat      = MAILBOX_FIFOSTATUS(3),
 324        },
 325        .rx_fifo = {
 326                .msg            = MAILBOX_MESSAGE(2),
 327                .msg_stat       = MAILBOX_MSGSTATUS(2),
 328        },
 329        .irqenable      = OMAP4_MAILBOX_IRQENABLE(0),
 330        .irqstatus      = OMAP4_MAILBOX_IRQSTATUS(0),
 331        .notfull_bit    = MAILBOX_IRQ_NOTFULL(3),
 332        .newmsg_bit     = MAILBOX_IRQ_NEWMSG(2),
 333        .irqdisable     = OMAP4_MAILBOX_IRQENABLE_CLR(0),
 334};
 335
 336struct omap_mbox mbox_2_info = {
 337        .name   = "mailbox-2",
 338        .ops    = &omap2_mbox_ops,
 339        .priv   = &omap2_mbox_2_priv,
 340};
 341
 342struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL };
 343#endif
 344
 345static int __devinit omap2_mbox_probe(struct platform_device *pdev)
 346{
 347        struct resource *mem;
 348        int ret;
 349        struct omap_mbox **list;
 350
 351        if (false)
 352                ;
 353#if defined(CONFIG_ARCH_OMAP3)
 354        else if (cpu_is_omap34xx()) {
 355                list = omap3_mboxes;
 356
 357                list[0]->irq = platform_get_irq(pdev, 0);
 358        }
 359#endif
 360#if defined(CONFIG_ARCH_OMAP2)
 361        else if (cpu_is_omap2430()) {
 362                list = omap2_mboxes;
 363
 364                list[0]->irq = platform_get_irq(pdev, 0);
 365        } else if (cpu_is_omap2420()) {
 366                list = omap2_mboxes;
 367
 368                list[0]->irq = platform_get_irq_byname(pdev, "dsp");
 369                list[1]->irq = platform_get_irq_byname(pdev, "iva");
 370        }
 371#endif
 372#if defined(CONFIG_ARCH_OMAP4)
 373        else if (cpu_is_omap44xx()) {
 374                list = omap4_mboxes;
 375
 376                list[0]->irq = list[1]->irq = platform_get_irq(pdev, 0);
 377        }
 378#endif
 379        else {
 380                pr_err("%s: platform not supported\n", __func__);
 381                return -ENODEV;
 382        }
 383
 384        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 385        mbox_base = ioremap(mem->start, resource_size(mem));
 386        if (!mbox_base)
 387                return -ENOMEM;
 388
 389        ret = omap_mbox_register(&pdev->dev, list);
 390        if (ret) {
 391                iounmap(mbox_base);
 392                return ret;
 393        }
 394
 395        return 0;
 396}
 397
 398static int __devexit omap2_mbox_remove(struct platform_device *pdev)
 399{
 400        omap_mbox_unregister();
 401        iounmap(mbox_base);
 402        return 0;
 403}
 404
 405static struct platform_driver omap2_mbox_driver = {
 406        .probe = omap2_mbox_probe,
 407        .remove = __devexit_p(omap2_mbox_remove),
 408        .driver = {
 409                .name = "omap-mailbox",
 410        },
 411};
 412
 413static int __init omap2_mbox_init(void)
 414{
 415        return platform_driver_register(&omap2_mbox_driver);
 416}
 417
 418static void __exit omap2_mbox_exit(void)
 419{
 420        platform_driver_unregister(&omap2_mbox_driver);
 421}
 422
 423module_init(omap2_mbox_init);
 424module_exit(omap2_mbox_exit);
 425
 426MODULE_LICENSE("GPL v2");
 427MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
 428MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
 429MODULE_AUTHOR("Paul Mundt");
 430MODULE_ALIAS("platform:omap2-mailbox");
 431