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