mailbox: msm_qmp: Add apcs or ipcc interrupt support

Add support to trigger outgoing interrupts by using the mailbox
interface. This is supported when using the apcs-ipc or ipcc driver
to interface outgoing interrupts.

Change-Id: Id368b1cfac8a9f3fd445ed2265de16aa5d7c6d5c
Signed-off-by: Chris Lew <clew@codeaurora.org>
This commit is contained in:
Chris Lew
2018-11-30 18:52:09 -08:00
parent 8930333b8a
commit da2d9a634a

View File

@@ -10,6 +10,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mailbox_controller.h> #include <linux/mailbox_controller.h>
#include <linux/mailbox_client.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
@@ -200,6 +201,9 @@ struct qmp_device {
u32 tx_irq_count; u32 tx_irq_count;
u32 rx_irq_count; u32 rx_irq_count;
struct mbox_client mbox_client;
struct mbox_chan *mbox_chan;
void *ilc; void *ilc;
}; };
@@ -214,7 +218,13 @@ static void send_irq(struct qmp_device *mdev)
* before the interrupt is triggered * before the interrupt is triggered
*/ */
wmb(); wmb();
if (mdev->mbox_chan) {
mbox_send_message(mdev->mbox_chan, NULL);
mbox_client_txdone(mdev->mbox_chan, 0);
} else {
writel_relaxed(mdev->irq_mask, mdev->tx_irq_reg); writel_relaxed(mdev->irq_mask, mdev->tx_irq_reg);
}
mdev->tx_irq_count++; mdev->tx_irq_count++;
} }
@@ -849,6 +859,34 @@ static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev)
return 0; return 0;
} }
static int qmp_parse_ipc(struct platform_device *pdev)
{
struct qmp_device *mdev = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
struct resource *res;
int rc;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"irq-reg-base");
if (!res) {
pr_err("%s: missing key irq-reg-base\n", __func__);
return -ENODEV;
}
rc = of_property_read_u32(node, "qcom,irq-mask", &mdev->irq_mask);
if (rc) {
pr_err("%s: missing key qcom,irq-mask\n", __func__);
return -ENODEV;
}
mdev->tx_irq_reg = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!mdev->tx_irq_reg) {
pr_err("%s: unable to map tx irq reg\n", __func__);
return -EIO;
}
return 0;
}
/** /**
* qmp_edge_init() - Parse the device tree information for QMP, map io * qmp_edge_init() - Parse the device tree information for QMP, map io
@@ -861,7 +899,7 @@ static int qmp_edge_init(struct platform_device *pdev)
{ {
struct qmp_device *mdev = platform_get_drvdata(pdev); struct qmp_device *mdev = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct resource *msgram_r, *tx_irq_reg_r; struct resource *msgram_r;
char *key; char *key;
int rc; int rc;
@@ -879,18 +917,18 @@ static int qmp_edge_init(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
key = "irq-reg-base"; mdev->mbox_client.dev = &pdev->dev;
tx_irq_reg_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key); mdev->mbox_client.knows_txdone = true;
if (!tx_irq_reg_r) { mdev->mbox_chan = mbox_request_channel(&mdev->mbox_client, 0);
pr_err("%s: missing key %s\n", __func__, key); if (IS_ERR(mdev->mbox_chan)) {
return -ENODEV; if (PTR_ERR(mdev->mbox_chan) != -ENODEV)
} return PTR_ERR(mdev->mbox_chan);
key = "qcom,irq-mask"; mdev->mbox_chan = NULL;
rc = of_property_read_u32(node, key, &mdev->irq_mask);
if (rc) { rc = qmp_parse_ipc(pdev);
pr_err("%s: missing key %s\n", __func__, key); if (rc)
return -ENODEV; return rc;
} }
key = "interrupts"; key = "interrupts";
@@ -901,11 +939,9 @@ static int qmp_edge_init(struct platform_device *pdev)
} }
mdev->dev = &pdev->dev; mdev->dev = &pdev->dev;
mdev->tx_irq_reg = devm_ioremap_nocache(&pdev->dev, tx_irq_reg_r->start,
resource_size(tx_irq_reg_r));
mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start, mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start,
resource_size(msgram_r)); resource_size(msgram_r));
if (!mdev->msgram || !mdev->tx_irq_reg) if (!mdev->msgram)
return -EIO; return -EIO;
INIT_LIST_HEAD(&mdev->mboxes); INIT_LIST_HEAD(&mdev->mboxes);