From da2d9a634a088a39f34a245af09fa71865000568 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 30 Nov 2018 18:52:09 -0800 Subject: [PATCH] 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 --- drivers/mailbox/msm_qmp.c | 68 ++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c index 133a9aaaa784..40ec34dd0b9f 100644 --- a/drivers/mailbox/msm_qmp.c +++ b/drivers/mailbox/msm_qmp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -200,6 +201,9 @@ struct qmp_device { u32 tx_irq_count; u32 rx_irq_count; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + void *ilc; }; @@ -214,7 +218,13 @@ static void send_irq(struct qmp_device *mdev) * before the interrupt is triggered */ wmb(); - writel_relaxed(mdev->irq_mask, mdev->tx_irq_reg); + + 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); + } mdev->tx_irq_count++; } @@ -849,6 +859,34 @@ static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev) 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 @@ -861,7 +899,7 @@ static int qmp_edge_init(struct platform_device *pdev) { struct qmp_device *mdev = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct resource *msgram_r, *tx_irq_reg_r; + struct resource *msgram_r; char *key; int rc; @@ -879,18 +917,18 @@ static int qmp_edge_init(struct platform_device *pdev) return -ENODEV; } - key = "irq-reg-base"; - tx_irq_reg_r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key); - if (!tx_irq_reg_r) { - pr_err("%s: missing key %s\n", __func__, key); - return -ENODEV; - } + mdev->mbox_client.dev = &pdev->dev; + mdev->mbox_client.knows_txdone = true; + mdev->mbox_chan = mbox_request_channel(&mdev->mbox_client, 0); + if (IS_ERR(mdev->mbox_chan)) { + if (PTR_ERR(mdev->mbox_chan) != -ENODEV) + return PTR_ERR(mdev->mbox_chan); - key = "qcom,irq-mask"; - rc = of_property_read_u32(node, key, &mdev->irq_mask); - if (rc) { - pr_err("%s: missing key %s\n", __func__, key); - return -ENODEV; + mdev->mbox_chan = NULL; + + rc = qmp_parse_ipc(pdev); + if (rc) + return rc; } key = "interrupts"; @@ -901,11 +939,9 @@ static int qmp_edge_init(struct platform_device *pdev) } 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, resource_size(msgram_r)); - if (!mdev->msgram || !mdev->tx_irq_reg) + if (!mdev->msgram) return -EIO; INIT_LIST_HEAD(&mdev->mboxes);