Signed-off-by: Courtney Cavin <courtney.cavin@xxxxxxxxxxxxxx> --- drivers/mailbox/Kconfig | 1 - drivers/mailbox/mailbox-omap2.c | 315 +++++++++++++++++----------------------- 2 files changed, 132 insertions(+), 184 deletions(-) diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index ae6b09b..a592a5a 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -27,7 +27,6 @@ config OMAP1_MBOX config OMAP2PLUS_MBOX tristate "OMAP2+ Mailbox framework support" depends on ARCH_OMAP2PLUS - depends on BROKEN help Mailbox implementation for OMAP family chips with hardware for interprocessor communication involving DSP, IVA1.0 and IVA2 in diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c index 42d2b89..7ddde19 100644 --- a/drivers/mailbox/mailbox-omap2.c +++ b/drivers/mailbox/mailbox-omap2.c @@ -18,8 +18,8 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/platform_data/mailbox-omap.h> - -#include "omap-mbox.h" +#include <linux/interrupt.h> +#include <linux/mbox.h> #define MAILBOX_REVISION 0x000 #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) @@ -42,192 +42,165 @@ #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 omap2_mbox; + struct omap_mbox2_priv { + struct omap2_mbox *mbox; + int irq; + 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); -} +struct omap2_mbox { + struct mbox_adapter adapter; + struct completion completion; + void __iomem *base; + atomic_t active; + struct omap_mbox2_priv *priv; +}; -static inline void mbox_write_reg(u32 val, size_t ofs) +static inline unsigned int mbox_read_reg(void __iomem *base, size_t ofs) { - __raw_writel(val, mbox_base + ofs); + return __raw_readl(base + ofs); } -/* Mailbox H/W preparations */ -static int omap2_mbox_startup(struct omap_mbox *mbox) +static inline void mbox_write_reg(void __iomem *base, u32 val, size_t ofs) { - 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; + __raw_writel(val, base + ofs); } -static void omap2_mbox_shutdown(struct omap_mbox *mbox) +static int omap2_mbox_request(struct mbox_adapter *adap, + struct mbox_channel *chan) { - pm_runtime_put_sync(mbox->dev->parent); - pm_runtime_disable(mbox->dev->parent); -} + struct omap_mbox2_priv *p; + struct omap2_mbox *mbox; + u32 enable; -/* 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); -} + mbox = container_of(adap, struct omap2_mbox, adapter); + p = &mbox->priv[chan->id]; -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); -} + if (atomic_inc_return(&mbox->active) == 1) { + pm_runtime_enable(adap->dev); + pm_runtime_get_sync(adap->dev); + } -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); -} + enable = mbox_read_reg(mbox->base, p->irqenable); + enable |= p->notfull_bit | p->newmsg_bit; + mbox_write_reg(mbox->base, enable, p->irqenable); -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); + return 0; } -/* Mailbox IRQ handle functions */ -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +static int omap2_mbox_release(struct mbox_adapter *adap, + struct mbox_channel *chan) { - struct omap_mbox2_priv *p = mbox->priv; - u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + struct omap_mbox2_priv *p; + struct omap2_mbox *mbox; + u32 disable; - l = mbox_read_reg(p->irqenable); - l |= bit; - mbox_write_reg(l, p->irqenable); -} + mbox = container_of(adap, struct omap2_mbox, adapter); + p = &mbox->priv[chan->id]; -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; + disable = 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; + disable = mbox_read_reg(mbox->base, p->irqdisable) & ~disable; + mbox_write_reg(mbox->base, disable, p->irqdisable); - mbox_write_reg(bit, p->irqdisable); + if (atomic_dec_return(&mbox->active) == 0) { + pm_runtime_put_sync(adap->dev); + pm_runtime_disable(adap->dev); + } + return 0; } -static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +static int omap2_mbox_put_message(struct mbox_adapter *adap, + struct mbox_channel *chan, const void *data, unsigned int len) { - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + struct omap_mbox2_fifo *fifo; + struct omap2_mbox *mbox; + int ret; + u32 msg; - mbox_write_reg(bit, p->irqstatus); + if (len != sizeof(msg)) + return -EINVAL; - /* Flush posted write for irq status to avoid spurious interrupts */ - mbox_read_reg(p->irqstatus); -} + msg = ((u32 *)data)[0]; + mbox = container_of(adap, struct omap2_mbox, adapter); + fifo = &mbox->priv[chan->id].tx_fifo; -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); + while (mbox_read_reg(mbox->base, fifo->fifo_stat)) { + ret = wait_for_completion_timeout(&mbox->completion, + msecs_to_jiffies(2)); + if (!ret) + return -ETIMEDOUT; + } - return (int)(enable & status & bit); -} + mbox_write_reg(mbox->base, msg, fifo->msg); -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]); - } + return 0; } -static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) +static irqreturn_t omap2_mbox_irq(int irq, void *dev) { - 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]); + struct mbox_channel *chan; + struct omap_mbox2_priv *p = dev; + struct omap2_mbox *mbox; + u32 status; + + mbox = p->mbox; + status = mbox_read_reg(mbox->base, p->irqstatus); + status &= mbox_read_reg(mbox->base, p->irqenable); + + chan = &mbox->adapter.channels[p - mbox->priv]; + + if (status & p->notfull_bit) { + complete(&mbox->completion); + mbox_write_reg(mbox->base, p->newmsg_bit, p->notfull_bit); + } else if (status & p->newmsg_bit) { + u32 msg = mbox_read_reg(mbox->base, p->rx_fifo.msg); + mbox_channel_notify(chan, &msg, sizeof(msg)); + mbox_write_reg(mbox->base, p->newmsg_bit, p->irqstatus); } + + /* Flush posted write for irq status to avoid spurious interrupts */ + mbox_read_reg(mbox->base, p->irqstatus); + + return IRQ_HANDLED; } -static struct omap_mbox_ops omap2_mbox_ops = { - .type = OMAP_MBOX_TYPE2, - .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 const struct mbox_adapter_ops omap2_mbox_ops = { + .owner = THIS_MODULE, + .request = omap2_mbox_request, + .release = omap2_mbox_release, + .put_message = omap2_mbox_put_message, }; 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_mbox2_priv *priv, *privblk; struct omap_mbox_dev_info *info; + struct omap2_mbox *mbox; + struct resource *mem; + int ret; int i; if (!pdata || !pdata->info_cnt || !pdata->info) { @@ -235,25 +208,22 @@ static int omap2_mbox_probe(struct platform_device *pdev) return -ENODEV; } - /* allocate one extra for marking end of list */ - list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); - if (!list) + mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) return -ENOMEM; - mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL); - if (!mboxblk) { - ret = -ENOMEM; - goto free_list; - } + atomic_set(&mbox->active, 0); + init_completion(&mbox->completion); - privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL); - if (!privblk) { - ret = -ENOMEM; - goto free_mboxblk; - } + privblk = devm_kzalloc(&pdev->dev, + pdata->info_cnt * sizeof(*priv), GFP_KERNEL); + if (!privblk) + return -ENOMEM; + priv = privblk; info = pdata->info; for (i = 0; i < pdata->info_cnt; i++, info++, priv++) { + priv->mbox = mbox; 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); @@ -272,61 +242,40 @@ static int omap2_mbox_probe(struct platform_device *pdev) } priv->intr_type = pdata->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) { - ret = mbox->irq; - goto free_privblk; - } - list[i] = mbox++; + priv->irq = platform_get_irq(pdev, info->irq_id); + if (priv->irq < 0) + return priv->irq; + + ret = devm_request_irq(&pdev->dev, priv->irq, + omap2_mbox_irq, IRQF_SHARED, info->name, priv); + if (ret < 0) + return ret; } + mbox->priv = privblk; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - ret = -ENOENT; - goto free_privblk; - } + if (!mem) + return -ENOENT; - mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) { - ret = -ENOMEM; - goto free_privblk; - } + mbox->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!mbox->base) + return -ENOMEM; - ret = omap_mbox_register(&pdev->dev, list); + mbox->adapter.nchannels = pdata->info_cnt; + mbox->adapter.ops = &omap2_mbox_ops; + mbox->adapter.dev = &pdev->dev; + ret = mbox_adapter_add(&mbox->adapter); if (ret) - goto unmap_mbox; - platform_set_drvdata(pdev, list); + return ret; + platform_set_drvdata(pdev, mbox); return 0; - -unmap_mbox: - iounmap(mbox_base); -free_privblk: - kfree(privblk); -free_mboxblk: - kfree(mboxblk); -free_list: - kfree(list); - return ret; } static int omap2_mbox_remove(struct platform_device *pdev) { - struct omap_mbox2_priv *privblk; - struct omap_mbox **list = platform_get_drvdata(pdev); - struct omap_mbox *mboxblk = list[0]; - - privblk = mboxblk->priv; - omap_mbox_unregister(); - iounmap(mbox_base); - kfree(privblk); - kfree(mboxblk); - kfree(list); - - return 0; + struct omap2_mbox *mbox = platform_get_drvdata(pdev); + return mbox_adapter_remove(&mbox->adapter); } static struct platform_driver omap2_mbox_driver = { -- 1.8.1.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html