[PATCHv3 7/8] mailbox/omap: add code to support the wkupm3 operations

Suman Anna s-anna at ti.com
Tue Aug 6 17:40:38 EDT 2013


The WkupM3 mailbox used for triggering PM operations such as suspend
and resume on AM33x/AM43x is special in that the M3 processor cannot
access the mailbox registers. However, an interrupt is needed to be
sent to request the M3 to perform a desired PM operation. This patch
adds the support for this special mailbox through separate ops for
this mailbox. These ops are designed to have the WkupM3's Rx interrupt
programmed within the driver, during transmission of a message. The
message is immediately read back and the internal mailbox interrupt
acknowledged as well to avoid triggering any spurious interrupts to
the M3.

Signed-off-by: Suman Anna <s-anna at ti.com>
---
 drivers/mailbox/mailbox-omap2.c | 87 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 86 insertions(+), 1 deletion(-)

diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c
index fef18f4..00ac2a2 100644
--- a/drivers/mailbox/mailbox-omap2.c
+++ b/drivers/mailbox/mailbox-omap2.c
@@ -36,6 +36,8 @@
 #define MAILBOX_IRQ_NEWMSG(m)		(1 << (2 * (m)))
 #define MAILBOX_IRQ_NOTFULL(m)		(1 << (2 * (m) + 1))
 
+#define AM33X_MBOX_WKUPM3_USR		3
+
 #define MBOX_REG_SIZE			0x120
 
 #define OMAP4_MBOX_REG_SIZE		0x130
@@ -179,6 +181,57 @@ static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
 	return (int)(enable & status & bit);
 }
 
+static void wkupm3_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;
+	unsigned long irqenable = ((irq == IRQ_RX) ?
+		OMAP4_MAILBOX_IRQENABLE(AM33X_MBOX_WKUPM3_USR) : p->irqenable);
+
+	l = mbox_read_reg(mbox->parent, irqenable);
+	l |= bit;
+	mbox_write_reg(mbox->parent, l, irqenable);
+}
+
+static void wkupm3_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;
+	unsigned long irqdisable = ((irq == IRQ_RX) ?
+	    OMAP4_MAILBOX_IRQENABLE_CLR(AM33X_MBOX_WKUPM3_USR) : p->irqdisable);
+
+	mbox_write_reg(mbox->parent, bit, irqdisable);
+}
+
+static void wkupm3_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;
+	unsigned long irqstatus = ((irq == IRQ_RX) ?
+		OMAP4_MAILBOX_IRQSTATUS(AM33X_MBOX_WKUPM3_USR) : p->irqstatus);
+
+	mbox_write_reg(mbox->parent, bit, irqstatus);
+
+	/* Flush posted write for irq status to avoid spurious interrupts */
+	mbox_read_reg(mbox->parent, irqstatus);
+}
+
+static int wkupm3_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, status;
+
+	/* WkupM3 mailbox does not use a receive queue */
+	if (irq == IRQ_RX)
+		return 0;
+
+	enable = mbox_read_reg(mbox->parent, p->irqenable);
+	status = mbox_read_reg(mbox->parent, p->irqstatus);
+
+	return (int)(enable & status & bit);
+}
+
 static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
 {
 	int i;
@@ -215,6 +268,20 @@ static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
 	}
 }
 
+static void wkupm3_mbox_send_data(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	mbox_msg_t rmsg;
+
+	/* enable the mbox Rx interrupt for WkupM3 only briefly */
+	wkupm3_mbox_enable_irq(mbox, IRQ_RX);
+	omap2_mbox_fifo_write(mbox, msg);
+	wkupm3_mbox_disable_irq(mbox, IRQ_RX);
+
+	/* read back the message and ack the interrupt on behalf of WkupM3 */
+	rmsg = omap2_mbox_fifo_read(mbox);
+	wkupm3_mbox_ack_irq(mbox, IRQ_RX);
+}
+
 static struct omap_mbox_ops omap2_mbox_ops = {
 	.startup	= omap2_mbox_startup,
 	.shutdown	= omap2_mbox_shutdown,
@@ -230,6 +297,21 @@ static struct omap_mbox_ops omap2_mbox_ops = {
 	.restore_ctx	= omap2_mbox_restore_ctx,
 };
 
+static struct omap_mbox_ops wkupm3_mbox_ops = {
+	.startup	= omap2_mbox_startup,
+	.shutdown	= omap2_mbox_shutdown,
+	.fifo_read	= omap2_mbox_fifo_read,
+	.fifo_write	= wkupm3_mbox_send_data,
+	.fifo_empty	= omap2_mbox_fifo_empty,
+	.poll_for_space	= omap2_mbox_poll_for_space,
+	.enable_irq	= wkupm3_mbox_enable_irq,
+	.disable_irq	= wkupm3_mbox_disable_irq,
+	.ack_irq	= wkupm3_mbox_ack_irq,
+	.is_irq		= wkupm3_mbox_is_irq,
+	.save_ctx	= omap2_mbox_save_ctx,
+	.restore_ctx	= omap2_mbox_restore_ctx,
+};
+
 static const struct of_device_id omap_mailbox_of_match[] = {
 	{
 		.compatible	= "ti,omap2-mailbox",
@@ -387,7 +469,10 @@ static int omap2_mbox_probe(struct platform_device *pdev)
 		mbox->priv = priv;
 		mbox->parent = mdev;
 		mbox->name = info->name;
-		mbox->ops = &omap2_mbox_ops;
+		if (!strcmp(mbox->name, "wkup_m3"))
+			mbox->ops = &wkupm3_mbox_ops;
+		else
+			mbox->ops = &omap2_mbox_ops;
 		mbox->irq = platform_get_irq(pdev, info->irq_id);
 		if (mbox->irq < 0) {
 			ret = mbox->irq;
-- 
1.8.3.3




More information about the linux-arm-kernel mailing list