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