mailbox/omap: consolidate OMAP mailbox driver

There is no need for a separate common OMAP mailbox module
now that the OMAP1 mailbox driver has been removed. So,
consolidate the two individual OMAP mailbox modules into a
single driver. This streamlines the driver for converting
to mailbox framework.

The following are the main changes:
- collapse mailbox-omap2.c into omap-mailbox.c
- remove omap_mbox_ops and replace the ops calls with
  the equivalent functionality.
- simplify the sub-mailbox startup/shutdown functionality,
  the one-time operations are moved into probe, and the
  pm_runtime_get_sync and pm_runtime_put_sync can be invoked
  without using a configuration counter.
- move all definitions from private omap_mbox.h into the
  source code, and eliminate this internal header.
- rename some variables that used the omap2_mbox prefix with
  a generic omap_mbox prefix.

Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
This commit is contained in:
Suman Anna 2014-06-24 19:43:41 -05:00 committed by Tony Lindgren
parent ef45eae6e9
commit 5040f53438
5 changed files with 281 additions and 453 deletions

View File

@ -16,17 +16,9 @@ config PL320_MBOX
Management Engine, primarily for cpufreq. Say Y here if you want Management Engine, primarily for cpufreq. Say Y here if you want
to use the PL320 IPCM support. to use the PL320 IPCM support.
config OMAP_MBOX
tristate
help
This option is selected by any OMAP architecture specific mailbox
driver such as CONFIG_OMAP2PLUS_MBOX. This enables the common OMAP
mailbox framework code.
config OMAP2PLUS_MBOX config OMAP2PLUS_MBOX
tristate "OMAP2+ Mailbox framework support" tristate "OMAP2+ Mailbox framework support"
depends on ARCH_OMAP2PLUS depends on ARCH_OMAP2PLUS
select OMAP_MBOX
help help
Mailbox implementation for OMAP family chips with hardware for Mailbox implementation for OMAP family chips with hardware for
interprocessor communication involving DSP, IVA1.0 and IVA2 in interprocessor communication involving DSP, IVA1.0 and IVA2 in

View File

@ -1,5 +1,3 @@
obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
obj-$(CONFIG_OMAP_MBOX) += omap-mailbox.o obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
obj-$(CONFIG_OMAP2PLUS_MBOX) += mailbox_omap2.o
mailbox_omap2-objs := mailbox-omap2.o

View File

@ -1,333 +0,0 @@
/*
* Mailbox reservation modules for OMAP2/3
*
* Copyright (C) 2006-2009 Nokia Corporation
* Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
* and Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mailbox-omap.h>
#include "omap-mbox.h"
#define MAILBOX_REVISION 0x000
#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
#define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
#define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
#define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \
OMAP2_MAILBOX_IRQSTATUS(u))
#define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \
OMAP2_MAILBOX_IRQENABLE(u))
#define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \
: OMAP2_MAILBOX_IRQENABLE(u))
#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
#define MBOX_REG_SIZE 0x120
#define OMAP4_MBOX_REG_SIZE 0x130
#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
static void __iomem *mbox_base;
struct omap_mbox2_fifo {
unsigned long msg;
unsigned long fifo_stat;
unsigned long msg_stat;
};
struct omap_mbox2_priv {
struct omap_mbox2_fifo tx_fifo;
struct omap_mbox2_fifo rx_fifo;
unsigned long irqenable;
unsigned long irqstatus;
u32 newmsg_bit;
u32 notfull_bit;
u32 ctx[OMAP4_MBOX_NR_REGS];
unsigned long irqdisable;
u32 intr_type;
};
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 int omap2_mbox_startup(struct omap_mbox *mbox)
{
u32 l;
pm_runtime_enable(mbox->dev->parent);
pm_runtime_get_sync(mbox->dev->parent);
l = mbox_read_reg(MAILBOX_REVISION);
pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
return 0;
}
static void omap2_mbox_shutdown(struct omap_mbox *mbox)
{
pm_runtime_put_sync(mbox->dev->parent);
pm_runtime_disable(mbox->dev->parent);
}
/* Mailbox FIFO handle functions */
static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
return (mbox_msg_t) mbox_read_reg(fifo->msg);
}
static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
mbox_write_reg(msg, fifo->msg);
}
static int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
return (mbox_read_reg(fifo->msg_stat) == 0);
}
static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
{
struct omap_mbox2_fifo *fifo =
&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
return mbox_read_reg(fifo->fifo_stat);
}
/* Mailbox IRQ handle functions */
static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
struct omap_mbox2_priv *p = mbox->priv;
u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
l = mbox_read_reg(p->irqenable);
l |= bit;
mbox_write_reg(l, p->irqenable);
}
static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
struct omap_mbox2_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
/*
* Read and update the interrupt configuration register for pre-OMAP4.
* OMAP4 and later SoCs have a dedicated interrupt disabling register.
*/
if (!p->intr_type)
bit = mbox_read_reg(p->irqdisable) & ~bit;
mbox_write_reg(bit, p->irqdisable);
}
static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
struct omap_mbox2_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
mbox_write_reg(bit, p->irqstatus);
/* Flush posted write for irq status to avoid spurious interrupts */
mbox_read_reg(p->irqstatus);
}
static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
struct omap_mbox2_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
u32 enable = mbox_read_reg(p->irqenable);
u32 status = mbox_read_reg(p->irqstatus);
return (int)(enable & status & bit);
}
static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
{
int i;
struct omap_mbox2_priv *p = mbox->priv;
int nr_regs;
if (p->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
else
nr_regs = MBOX_NR_REGS;
for (i = 0; i < nr_regs; i++) {
p->ctx[i] = mbox_read_reg(i * sizeof(u32));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
i, p->ctx[i]);
}
}
static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
{
int i;
struct omap_mbox2_priv *p = mbox->priv;
int nr_regs;
if (p->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
else
nr_regs = MBOX_NR_REGS;
for (i = 0; i < nr_regs; i++) {
mbox_write_reg(p->ctx[i], i * sizeof(u32));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
i, p->ctx[i]);
}
}
static struct omap_mbox_ops omap2_mbox_ops = {
.startup = omap2_mbox_startup,
.shutdown = omap2_mbox_shutdown,
.fifo_read = omap2_mbox_fifo_read,
.fifo_write = omap2_mbox_fifo_write,
.fifo_empty = omap2_mbox_fifo_empty,
.fifo_full = omap2_mbox_fifo_full,
.enable_irq = omap2_mbox_enable_irq,
.disable_irq = omap2_mbox_disable_irq,
.ack_irq = omap2_mbox_ack_irq,
.is_irq = omap2_mbox_is_irq,
.save_ctx = omap2_mbox_save_ctx,
.restore_ctx = omap2_mbox_restore_ctx,
};
static int omap2_mbox_probe(struct platform_device *pdev)
{
struct resource *mem;
int ret;
struct omap_mbox **list, *mbox, *mboxblk;
struct omap_mbox2_priv *priv, *privblk;
struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
struct omap_mbox_dev_info *info;
u32 intr_type;
int i;
if (!pdata || !pdata->info_cnt || !pdata->info) {
pr_err("%s: platform not supported\n", __func__);
return -ENODEV;
}
/* allocate one extra for marking end of list */
list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
GFP_KERNEL);
if (!list)
return -ENOMEM;
mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
GFP_KERNEL);
if (!mboxblk)
return -ENOMEM;
privblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*priv),
GFP_KERNEL);
if (!privblk)
return -ENOMEM;
info = pdata->info;
intr_type = pdata->intr_type;
mbox = mboxblk;
priv = privblk;
for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
priv->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
priv->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
priv->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
priv->intr_type = intr_type;
mbox->priv = priv;
mbox->name = info->name;
mbox->ops = &omap2_mbox_ops;
mbox->irq = platform_get_irq(pdev, info->irq_id);
if (mbox->irq < 0)
return mbox->irq;
list[i] = mbox++;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mbox_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(mbox_base))
return PTR_ERR(mbox_base);
ret = omap_mbox_register(&pdev->dev, list);
if (ret)
return ret;
platform_set_drvdata(pdev, list);
return 0;
}
static int omap2_mbox_remove(struct platform_device *pdev)
{
omap_mbox_unregister();
return 0;
}
static struct platform_driver omap2_mbox_driver = {
.probe = omap2_mbox_probe,
.remove = omap2_mbox_remove,
.driver = {
.name = "omap-mailbox",
},
};
static int __init omap2_mbox_init(void)
{
return platform_driver_register(&omap2_mbox_driver);
}
static void __exit omap2_mbox_exit(void)
{
platform_driver_unregister(&omap2_mbox_driver);
}
module_init(omap2_mbox_init);
module_exit(omap2_mbox_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
MODULE_AUTHOR("Paul Mundt");
MODULE_ALIAS("platform:omap2-mailbox");

View File

@ -2,8 +2,10 @@
* OMAP mailbox driver * OMAP mailbox driver
* *
* Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
* Copyright (C) 2013-2014 Texas Instruments Inc.
* *
* Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
* Suman Anna <s-anna@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -29,45 +31,145 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mailbox-omap.h>
#include <linux/omap-mailbox.h>
#include "omap-mbox.h" #define MAILBOX_REVISION 0x000
#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
#define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
#define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
#define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \
OMAP2_MAILBOX_IRQSTATUS(u))
#define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \
OMAP2_MAILBOX_IRQENABLE(u))
#define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \
: OMAP2_MAILBOX_IRQENABLE(u))
#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
#define MBOX_REG_SIZE 0x120
#define OMAP4_MBOX_REG_SIZE 0x130
#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
struct omap_mbox_fifo {
unsigned long msg;
unsigned long fifo_stat;
unsigned long msg_stat;
};
struct omap_mbox_priv {
struct omap_mbox_fifo tx_fifo;
struct omap_mbox_fifo rx_fifo;
unsigned long irqenable;
unsigned long irqstatus;
u32 newmsg_bit;
u32 notfull_bit;
u32 ctx[OMAP4_MBOX_NR_REGS];
unsigned long irqdisable;
u32 intr_type;
};
struct omap_mbox_queue {
spinlock_t lock;
struct kfifo fifo;
struct work_struct work;
struct tasklet_struct tasklet;
struct omap_mbox *mbox;
bool full;
};
struct omap_mbox {
const char *name;
int irq;
struct omap_mbox_queue *txq, *rxq;
struct device *dev;
void *priv;
int use_count;
struct blocking_notifier_head notifier;
};
static void __iomem *mbox_base;
static struct omap_mbox **mboxes; static struct omap_mbox **mboxes;
static int mbox_configured;
static DEFINE_MUTEX(mbox_configured_lock); static DEFINE_MUTEX(mbox_configured_lock);
static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
module_param(mbox_kfifo_size, uint, S_IRUGO); module_param(mbox_kfifo_size, uint, S_IRUGO);
MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
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 FIFO handle functions */ /* Mailbox FIFO handle functions */
static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
{ {
return mbox->ops->fifo_read(mbox); struct omap_mbox_fifo *fifo =
&((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
return (mbox_msg_t) mbox_read_reg(fifo->msg);
} }
static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
{ {
mbox->ops->fifo_write(mbox, msg); struct omap_mbox_fifo *fifo =
&((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
mbox_write_reg(msg, fifo->msg);
} }
static inline int mbox_fifo_empty(struct omap_mbox *mbox)
static int mbox_fifo_empty(struct omap_mbox *mbox)
{ {
return mbox->ops->fifo_empty(mbox); struct omap_mbox_fifo *fifo =
&((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
return (mbox_read_reg(fifo->msg_stat) == 0);
} }
static inline int mbox_fifo_full(struct omap_mbox *mbox)
static int mbox_fifo_full(struct omap_mbox *mbox)
{ {
return mbox->ops->fifo_full(mbox); struct omap_mbox_fifo *fifo =
&((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
return mbox_read_reg(fifo->fifo_stat);
} }
/* Mailbox IRQ handle functions */ /* Mailbox IRQ handle functions */
static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{ {
if (mbox->ops->ack_irq) struct omap_mbox_priv *p = mbox->priv;
mbox->ops->ack_irq(mbox, irq); u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
mbox_write_reg(bit, p->irqstatus);
/* Flush posted write for irq status to avoid spurious interrupts */
mbox_read_reg(p->irqstatus);
} }
static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{ {
return mbox->ops->is_irq(mbox, irq); struct omap_mbox_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
u32 enable = mbox_read_reg(p->irqenable);
u32 status = mbox_read_reg(p->irqstatus);
return (int)(enable & status & bit);
} }
/* /*
@ -103,35 +205,66 @@ EXPORT_SYMBOL(omap_mbox_msg_send);
void omap_mbox_save_ctx(struct omap_mbox *mbox) void omap_mbox_save_ctx(struct omap_mbox *mbox)
{ {
if (!mbox->ops->save_ctx) { int i;
dev_err(mbox->dev, "%s:\tno save\n", __func__); struct omap_mbox_priv *p = mbox->priv;
return; int nr_regs;
}
mbox->ops->save_ctx(mbox); if (p->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
else
nr_regs = MBOX_NR_REGS;
for (i = 0; i < nr_regs; i++) {
p->ctx[i] = mbox_read_reg(i * sizeof(u32));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
i, p->ctx[i]);
}
} }
EXPORT_SYMBOL(omap_mbox_save_ctx); EXPORT_SYMBOL(omap_mbox_save_ctx);
void omap_mbox_restore_ctx(struct omap_mbox *mbox) void omap_mbox_restore_ctx(struct omap_mbox *mbox)
{ {
if (!mbox->ops->restore_ctx) { int i;
dev_err(mbox->dev, "%s:\tno restore\n", __func__); struct omap_mbox_priv *p = mbox->priv;
return; int nr_regs;
}
mbox->ops->restore_ctx(mbox); if (p->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
else
nr_regs = MBOX_NR_REGS;
for (i = 0; i < nr_regs; i++) {
mbox_write_reg(p->ctx[i], i * sizeof(u32));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
i, p->ctx[i]);
}
} }
EXPORT_SYMBOL(omap_mbox_restore_ctx); EXPORT_SYMBOL(omap_mbox_restore_ctx);
void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{ {
mbox->ops->enable_irq(mbox, irq); struct omap_mbox_priv *p = mbox->priv;
u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
l = mbox_read_reg(p->irqenable);
l |= bit;
mbox_write_reg(l, p->irqenable);
} }
EXPORT_SYMBOL(omap_mbox_enable_irq); EXPORT_SYMBOL(omap_mbox_enable_irq);
void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{ {
mbox->ops->disable_irq(mbox, irq); struct omap_mbox_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
/*
* Read and update the interrupt configuration register for pre-OMAP4.
* OMAP4 and later SoCs have a dedicated interrupt disabling register.
*/
if (!p->intr_type)
bit = mbox_read_reg(p->irqdisable) & ~bit;
mbox_write_reg(bit, p->irqdisable);
} }
EXPORT_SYMBOL(omap_mbox_disable_irq); EXPORT_SYMBOL(omap_mbox_disable_irq);
@ -267,14 +400,9 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
struct omap_mbox_queue *mq; struct omap_mbox_queue *mq;
mutex_lock(&mbox_configured_lock); mutex_lock(&mbox_configured_lock);
if (!mbox_configured++) { ret = pm_runtime_get_sync(mbox->dev->parent);
if (likely(mbox->ops->startup)) { if (unlikely(ret < 0))
ret = mbox->ops->startup(mbox); goto fail_startup;
if (unlikely(ret))
goto fail_startup;
} else
goto fail_startup;
}
if (!mbox->use_count++) { if (!mbox->use_count++) {
mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
@ -309,11 +437,9 @@ fail_request_irq:
fail_alloc_rxq: fail_alloc_rxq:
mbox_queue_free(mbox->txq); mbox_queue_free(mbox->txq);
fail_alloc_txq: fail_alloc_txq:
if (mbox->ops->shutdown) pm_runtime_put_sync(mbox->dev->parent);
mbox->ops->shutdown(mbox);
mbox->use_count--; mbox->use_count--;
fail_startup: fail_startup:
mbox_configured--;
mutex_unlock(&mbox_configured_lock); mutex_unlock(&mbox_configured_lock);
return ret; return ret;
} }
@ -331,10 +457,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
mbox_queue_free(mbox->rxq); mbox_queue_free(mbox->rxq);
} }
if (likely(mbox->ops->shutdown)) { pm_runtime_put_sync(mbox->dev->parent);
if (!--mbox_configured)
mbox->ops->shutdown(mbox);
}
mutex_unlock(&mbox_configured_lock); mutex_unlock(&mbox_configured_lock);
} }
@ -379,7 +502,7 @@ EXPORT_SYMBOL(omap_mbox_put);
static struct class omap_mbox_class = { .name = "mbox", }; static struct class omap_mbox_class = { .name = "mbox", };
int omap_mbox_register(struct device *parent, struct omap_mbox **list) static int omap_mbox_register(struct device *parent, struct omap_mbox **list)
{ {
int ret; int ret;
int i; int i;
@ -406,9 +529,8 @@ err_out:
device_unregister(mboxes[i]->dev); device_unregister(mboxes[i]->dev);
return ret; return ret;
} }
EXPORT_SYMBOL(omap_mbox_register);
int omap_mbox_unregister(void) static int omap_mbox_unregister(void)
{ {
int i; int i;
@ -420,7 +542,117 @@ int omap_mbox_unregister(void)
mboxes = NULL; mboxes = NULL;
return 0; return 0;
} }
EXPORT_SYMBOL(omap_mbox_unregister);
static int omap_mbox_probe(struct platform_device *pdev)
{
struct resource *mem;
int ret;
struct omap_mbox **list, *mbox, *mboxblk;
struct omap_mbox_priv *priv, *privblk;
struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
struct omap_mbox_dev_info *info;
u32 intr_type;
u32 l;
int i;
if (!pdata || !pdata->info_cnt || !pdata->info) {
pr_err("%s: platform not supported\n", __func__);
return -ENODEV;
}
/* allocate one extra for marking end of list */
list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
GFP_KERNEL);
if (!list)
return -ENOMEM;
mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
GFP_KERNEL);
if (!mboxblk)
return -ENOMEM;
privblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*priv),
GFP_KERNEL);
if (!privblk)
return -ENOMEM;
info = pdata->info;
intr_type = pdata->intr_type;
mbox = mboxblk;
priv = privblk;
for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
priv->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
priv->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
priv->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
priv->intr_type = intr_type;
mbox->priv = priv;
mbox->name = info->name;
mbox->irq = platform_get_irq(pdev, info->irq_id);
if (mbox->irq < 0)
return mbox->irq;
list[i] = mbox++;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mbox_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(mbox_base))
return PTR_ERR(mbox_base);
ret = omap_mbox_register(&pdev->dev, list);
if (ret)
return ret;
platform_set_drvdata(pdev, list);
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&pdev->dev);
goto unregister;
}
/*
* just print the raw revision register, the format is not
* uniform across all SoCs
*/
l = mbox_read_reg(MAILBOX_REVISION);
dev_info(&pdev->dev, "omap mailbox rev 0x%x\n", l);
ret = pm_runtime_put_sync(&pdev->dev);
if (ret < 0)
goto unregister;
return 0;
unregister:
pm_runtime_disable(&pdev->dev);
omap_mbox_unregister();
return ret;
}
static int omap_mbox_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
omap_mbox_unregister();
return 0;
}
static struct platform_driver omap_mbox_driver = {
.probe = omap_mbox_probe,
.remove = omap_mbox_remove,
.driver = {
.name = "omap-mailbox",
.owner = THIS_MODULE,
},
};
static int __init omap_mbox_init(void) static int __init omap_mbox_init(void)
{ {
@ -435,12 +667,13 @@ static int __init omap_mbox_init(void)
mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
sizeof(mbox_msg_t)); sizeof(mbox_msg_t));
return 0; return platform_driver_register(&omap_mbox_driver);
} }
subsys_initcall(omap_mbox_init); subsys_initcall(omap_mbox_init);
static void __exit omap_mbox_exit(void) static void __exit omap_mbox_exit(void)
{ {
platform_driver_unregister(&omap_mbox_driver);
class_unregister(&omap_mbox_class); class_unregister(&omap_mbox_class);
} }
module_exit(omap_mbox_exit); module_exit(omap_mbox_exit);

View File

@ -1,62 +0,0 @@
/*
* omap-mbox.h: OMAP mailbox internal definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef OMAP_MBOX_H
#define OMAP_MBOX_H
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/omap-mailbox.h>
struct omap_mbox_ops {
int (*startup)(struct omap_mbox *mbox);
void (*shutdown)(struct omap_mbox *mbox);
/* fifo */
mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
int (*fifo_empty)(struct omap_mbox *mbox);
int (*fifo_full)(struct omap_mbox *mbox);
/* irq */
void (*enable_irq)(struct omap_mbox *mbox,
omap_mbox_irq_t irq);
void (*disable_irq)(struct omap_mbox *mbox,
omap_mbox_irq_t irq);
void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
/* ctx */
void (*save_ctx)(struct omap_mbox *mbox);
void (*restore_ctx)(struct omap_mbox *mbox);
};
struct omap_mbox_queue {
spinlock_t lock;
struct kfifo fifo;
struct work_struct work;
struct tasklet_struct tasklet;
struct omap_mbox *mbox;
bool full;
};
struct omap_mbox {
const char *name;
int irq;
struct omap_mbox_queue *txq, *rxq;
struct omap_mbox_ops *ops;
struct device *dev;
void *priv;
int use_count;
struct blocking_notifier_head notifier;
};
int omap_mbox_register(struct device *parent, struct omap_mbox **);
int omap_mbox_unregister(void);
#endif /* OMAP_MBOX_H */