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