[RFC 6/6] mailbox: omap2+: move to common mbox framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux