From 00d9990acb23c4319a1dc961d4e29a9213923b67 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Fri, 3 Apr 2020 11:52:08 +0800 Subject: [PATCH 01/18] mailbox: pcc: make pcc_mbox_driver static Fix the following sparse warning: drivers/mailbox/pcc.c:571:24: warning: symbol 'pcc_mbox_driver' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Jason Yan Signed-off-by: Jassi Brar --- drivers/mailbox/pcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 34844b7a3675..8c7fac38bb1c 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -568,7 +568,7 @@ static int pcc_mbox_probe(struct platform_device *pdev) return ret; } -struct platform_driver pcc_mbox_driver = { +static struct platform_driver pcc_mbox_driver = { .probe = pcc_mbox_probe, .driver = { .name = "PCCT", From 676f23eab75adbf72c029bdfb7b5a7b2f1129177 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 13 Apr 2020 20:25:30 +0800 Subject: [PATCH 02/18] mailbox: imx: Support runtime PM Some power hungry sub-systems like VPU has its own MUs which also use mailbox driver, current mailbox driver uses platform driver model and MU's power will be ON after driver probed and left ON there, it may cause the whole sub-system can NOT enter lower power mode, take VPU driver for example, it has runtime PM support, but due to its MU always ON, the VPU sub-system will be always ON and consume many power during kernel idle. To save power in kernel idle, mailbox driver needs to support runtime PM in order to power off MU when it is unused. However, the runtime suspend/resume can ONLY be implemented in mailbox's .shutdown/.startup callback, so its consumer needs to call mbox_request_channel()/mbox_free_channel() in consumer driver's runtime PM callback, then the MU's power will be ON/OFF along with consumer's runtime PM status. Signed-off-by: Anson Huang Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 7906624a731c..97bf0acf51d8 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x))) @@ -287,6 +288,7 @@ static int imx_mu_startup(struct mbox_chan *chan) struct imx_mu_con_priv *cp = chan->con_priv; int ret; + pm_runtime_get_sync(priv->dev); if (cp->type == IMX_MU_TYPE_TXDB) { /* Tx doorbell don't have ACK support */ tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet, @@ -323,6 +325,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan) if (cp->type == IMX_MU_TYPE_TXDB) { tasklet_kill(&cp->txdb_tasklet); + pm_runtime_put_sync(priv->dev); return; } @@ -341,6 +344,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan) } free_irq(priv->irq, chan); + pm_runtime_put_sync(priv->dev); } static const struct mbox_chan_ops imx_mu_ops = { @@ -508,7 +512,27 @@ static int imx_mu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - return devm_mbox_controller_register(dev, &priv->mbox); + ret = devm_mbox_controller_register(dev, &priv->mbox); + if (ret) + return ret; + + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + goto disable_runtime_pm; + } + + ret = pm_runtime_put_sync(dev); + if (ret < 0) + goto disable_runtime_pm; + + return 0; + +disable_runtime_pm: + pm_runtime_disable(dev); + return ret; } static int imx_mu_remove(struct platform_device *pdev) @@ -516,6 +540,7 @@ static int imx_mu_remove(struct platform_device *pdev) struct imx_mu_priv *priv = platform_get_drvdata(pdev); clk_disable_unprepare(priv->clk); + pm_runtime_disable(priv->dev); return 0; } From 1b3a347b7d56aa637157da1b7df225071af1421f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 7 Apr 2020 12:27:53 +0300 Subject: [PATCH 03/18] mailbox: imx: Fix return in imx_mu_scu_xlate() This called from mbox_request_channel(). The caller is expecting error pointers and not NULL so this "return NULL;" will lead to an Oops. Fixes: 0a67003b1985 ("mailbox: imx: add SCU MU support") Signed-off-by: Dan Carpenter Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 97bf0acf51d8..cacc60662f24 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -378,7 +378,7 @@ static struct mbox_chan *imx_mu_scu_xlate(struct mbox_controller *mbox, break; default: dev_err(mbox->dev, "Invalid chan type: %d\n", type); - return NULL; + return ERR_PTR(-EINVAL); } if (chan >= mbox->num_chans) { From 47303f9438954bc7bca593310ac8685d11297725 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 30 May 2020 17:56:28 -0500 Subject: [PATCH 04/18] mailbox: imx: Disable the clock on devm_mbox_controller_register() failure devm_mbox_controller_register() may fail, and in the case of failure the priv->clk clock that was previously enabled, should be disabled. Fixes: 2bb7005696e2 ("mailbox: Add support for i.MX messaging unit") Signed-off-by: Fabio Estevam Reviewed-by: Peng Fan Acked-by: Oleksij Rempel [Jassi: fixed merge/am conflict] Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index cacc60662f24..19f8d79cebac 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -513,8 +513,10 @@ static int imx_mu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); ret = devm_mbox_controller_register(dev, &priv->mbox); - if (ret) + if (ret) { + clk_disable_unprepare(priv->clk); return ret; + } pm_runtime_enable(dev); From ec32481b1669ad45480ae3b439e3dcde69bfaa68 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 5 Apr 2020 15:10:16 +0200 Subject: [PATCH 05/18] mailbox: ZynqMP IPI: Delete an error message in zynqmp_ipi_probe() The function platform_get_irq can log an error already. Thus omit a redundant message for the exception handling in the calling function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Jassi Brar --- drivers/mailbox/zynqmp-ipi-mailbox.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index 86887c9a349a..a4d176f160b8 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -668,10 +668,9 @@ static int zynqmp_ipi_probe(struct platform_device *pdev) /* IPI IRQ */ ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "unable to find IPI IRQ.\n"); + if (ret < 0) goto free_mbox_dev; - } + pdata->irq = ret; ret = devm_request_irq(dev, pdata->irq, zynqmp_ipi_interrupt, IRQF_SHARED, dev_name(dev), pdata); From fa75386538e5284a2e3ec2afe0c15c0532fb54d2 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 22 May 2020 21:31:08 +0800 Subject: [PATCH 06/18] dt-bindings: mailbox: Add the Spreadtrum mailbox documentation Add the Spreadtrum mailbox documentation. Reviewed-by: Rob Herring Signed-off-by: Baolin Wang Signed-off-by: Jassi Brar --- .../bindings/mailbox/sprd-mailbox.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/sprd-mailbox.yaml diff --git a/Documentation/devicetree/bindings/mailbox/sprd-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/sprd-mailbox.yaml new file mode 100644 index 000000000000..0f7451b42d7e --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/sprd-mailbox.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/mailbox/sprd-mailbox.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Spreadtrum mailbox controller bindings + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + enum: + - sprd,sc9860-mailbox + + reg: + items: + - description: inbox registers' base address + - description: outbox registers' base address + + interrupts: + items: + - description: inbox interrupt + - description: outbox interrupt + + clocks: + maxItems: 1 + + clock-names: + items: + - const: enable + + "#mbox-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - "#mbox-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + mailbox: mailbox@400a0000 { + compatible = "sprd,sc9860-mailbox"; + reg = <0 0x400a0000 0 0x8000>, <0 0x400a8000 0 0x8000>; + #mbox-cells = <1>; + clock-names = "enable"; + clocks = <&aon_gate 53>; + interrupts = , ; + }; +... From ca27fc26cd2219d964b4fc0efac634ab237b6c8e Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 22 May 2020 21:31:09 +0800 Subject: [PATCH 07/18] mailbox: sprd: Add Spreadtrum mailbox driver The Spreadtrum mailbox controller supports 8 channels to communicate with MCUs, and it contains 2 different parts: inbox and outbox, which are used to send and receive messages by IRQ mode. Signed-off-by: Baolin Wang Signed-off-by: Jassi Brar --- drivers/mailbox/Kconfig | 8 + drivers/mailbox/Makefile | 2 + drivers/mailbox/sprd-mailbox.c | 361 +++++++++++++++++++++++++++++++++ 3 files changed, 371 insertions(+) create mode 100644 drivers/mailbox/sprd-mailbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 5a577a6734cf..e03f3fb5caed 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -236,4 +236,12 @@ config SUN6I_MSGBOX various Allwinner SoCs. This mailbox is used for communication between the application CPUs and the power management coprocessor. +config SPRD_MBOX + tristate "Spreadtrum Mailbox" + depends on ARCH_SPRD || COMPILE_TEST + help + Mailbox driver implementation for the Spreadtrum platform. It is used + to send message between application processors and MCU. Say Y here if + you want to build the Spreatrum mailbox controller driver. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 2e4364ef5c47..9caf4ede6ce0 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -50,3 +50,5 @@ obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o + +obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o diff --git a/drivers/mailbox/sprd-mailbox.c b/drivers/mailbox/sprd-mailbox.c new file mode 100644 index 000000000000..f6fab24ae8a9 --- /dev/null +++ b/drivers/mailbox/sprd-mailbox.c @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Spreadtrum mailbox driver + * + * Copyright (c) 2020 Spreadtrum Communications Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPRD_MBOX_ID 0x0 +#define SPRD_MBOX_MSG_LOW 0x4 +#define SPRD_MBOX_MSG_HIGH 0x8 +#define SPRD_MBOX_TRIGGER 0xc +#define SPRD_MBOX_FIFO_RST 0x10 +#define SPRD_MBOX_FIFO_STS 0x14 +#define SPRD_MBOX_IRQ_STS 0x18 +#define SPRD_MBOX_IRQ_MSK 0x1c +#define SPRD_MBOX_LOCK 0x20 +#define SPRD_MBOX_FIFO_DEPTH 0x24 + +/* Bit and mask definiation for inbox's SPRD_MBOX_FIFO_STS register */ +#define SPRD_INBOX_FIFO_DELIVER_MASK GENMASK(23, 16) +#define SPRD_INBOX_FIFO_OVERLOW_MASK GENMASK(15, 8) +#define SPRD_INBOX_FIFO_DELIVER_SHIFT 16 +#define SPRD_INBOX_FIFO_BUSY_MASK GENMASK(7, 0) + +/* Bit and mask definiation for SPRD_MBOX_IRQ_STS register */ +#define SPRD_MBOX_IRQ_CLR BIT(0) + +/* Bit and mask definiation for outbox's SPRD_MBOX_FIFO_STS register */ +#define SPRD_OUTBOX_FIFO_FULL BIT(0) +#define SPRD_OUTBOX_FIFO_WR_SHIFT 16 +#define SPRD_OUTBOX_FIFO_RD_SHIFT 24 +#define SPRD_OUTBOX_FIFO_POS_MASK GENMASK(7, 0) + +/* Bit and mask definiation for inbox's SPRD_MBOX_IRQ_MSK register */ +#define SPRD_INBOX_FIFO_BLOCK_IRQ BIT(0) +#define SPRD_INBOX_FIFO_OVERFLOW_IRQ BIT(1) +#define SPRD_INBOX_FIFO_DELIVER_IRQ BIT(2) +#define SPRD_INBOX_FIFO_IRQ_MASK GENMASK(2, 0) + +/* Bit and mask definiation for outbox's SPRD_MBOX_IRQ_MSK register */ +#define SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ BIT(0) +#define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0) + +#define SPRD_MBOX_CHAN_MAX 8 + +struct sprd_mbox_priv { + struct mbox_controller mbox; + struct device *dev; + void __iomem *inbox_base; + void __iomem *outbox_base; + struct clk *clk; + u32 outbox_fifo_depth; + + struct mbox_chan chan[SPRD_MBOX_CHAN_MAX]; +}; + +static struct sprd_mbox_priv *to_sprd_mbox_priv(struct mbox_controller *mbox) +{ + return container_of(mbox, struct sprd_mbox_priv, mbox); +} + +static u32 sprd_mbox_get_fifo_len(struct sprd_mbox_priv *priv, u32 fifo_sts) +{ + u32 wr_pos = (fifo_sts >> SPRD_OUTBOX_FIFO_WR_SHIFT) & + SPRD_OUTBOX_FIFO_POS_MASK; + u32 rd_pos = (fifo_sts >> SPRD_OUTBOX_FIFO_RD_SHIFT) & + SPRD_OUTBOX_FIFO_POS_MASK; + u32 fifo_len; + + /* + * If the read pointer is equal with write pointer, which means the fifo + * is full or empty. + */ + if (wr_pos == rd_pos) { + if (fifo_sts & SPRD_OUTBOX_FIFO_FULL) + fifo_len = priv->outbox_fifo_depth; + else + fifo_len = 0; + } else if (wr_pos > rd_pos) { + fifo_len = wr_pos - rd_pos; + } else { + fifo_len = priv->outbox_fifo_depth - rd_pos + wr_pos; + } + + return fifo_len; +} + +static irqreturn_t sprd_mbox_outbox_isr(int irq, void *data) +{ + struct sprd_mbox_priv *priv = data; + struct mbox_chan *chan; + u32 fifo_sts, fifo_len, msg[2]; + int i, id; + + fifo_sts = readl(priv->outbox_base + SPRD_MBOX_FIFO_STS); + + fifo_len = sprd_mbox_get_fifo_len(priv, fifo_sts); + if (!fifo_len) { + dev_warn_ratelimited(priv->dev, "spurious outbox interrupt\n"); + return IRQ_NONE; + } + + for (i = 0; i < fifo_len; i++) { + msg[0] = readl(priv->outbox_base + SPRD_MBOX_MSG_LOW); + msg[1] = readl(priv->outbox_base + SPRD_MBOX_MSG_HIGH); + id = readl(priv->outbox_base + SPRD_MBOX_ID); + + chan = &priv->chan[id]; + mbox_chan_received_data(chan, (void *)msg); + + /* Trigger to update outbox FIFO pointer */ + writel(0x1, priv->outbox_base + SPRD_MBOX_TRIGGER); + } + + /* Clear irq status after reading all message. */ + writel(SPRD_MBOX_IRQ_CLR, priv->outbox_base + SPRD_MBOX_IRQ_STS); + + return IRQ_HANDLED; +} + +static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data) +{ + struct sprd_mbox_priv *priv = data; + struct mbox_chan *chan; + u32 fifo_sts, send_sts, busy, id; + + fifo_sts = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS); + + /* Get the inbox data delivery status */ + send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >> + SPRD_INBOX_FIFO_DELIVER_SHIFT; + if (!send_sts) { + dev_warn_ratelimited(priv->dev, "spurious inbox interrupt\n"); + return IRQ_NONE; + } + + while (send_sts) { + id = __ffs(send_sts); + send_sts &= (send_sts - 1); + + chan = &priv->chan[id]; + + /* + * Check if the message was fetched by remote traget, if yes, + * that means the transmission has been completed. + */ + busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK; + if (!(busy & BIT(id))) + mbox_chan_txdone(chan, 0); + } + + /* Clear FIFO delivery and overflow status */ + writel(fifo_sts & + (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK), + priv->inbox_base + SPRD_MBOX_FIFO_RST); + + /* Clear irq status */ + writel(SPRD_MBOX_IRQ_CLR, priv->inbox_base + SPRD_MBOX_IRQ_STS); + + return IRQ_HANDLED; +} + +static int sprd_mbox_send_data(struct mbox_chan *chan, void *msg) +{ + struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); + unsigned long id = (unsigned long)chan->con_priv; + u32 *data = msg; + + /* Write data into inbox FIFO, and only support 8 bytes every time */ + writel(data[0], priv->inbox_base + SPRD_MBOX_MSG_LOW); + writel(data[1], priv->inbox_base + SPRD_MBOX_MSG_HIGH); + + /* Set target core id */ + writel(id, priv->inbox_base + SPRD_MBOX_ID); + + /* Trigger remote request */ + writel(0x1, priv->inbox_base + SPRD_MBOX_TRIGGER); + + return 0; +} + +static int sprd_mbox_flush(struct mbox_chan *chan, unsigned long timeout) +{ + struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); + unsigned long id = (unsigned long)chan->con_priv; + u32 busy; + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_before(jiffies, timeout)) { + busy = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS) & + SPRD_INBOX_FIFO_BUSY_MASK; + if (!(busy & BIT(id))) { + mbox_chan_txdone(chan, 0); + return 0; + } + + udelay(1); + } + + return -ETIME; +} + +static int sprd_mbox_startup(struct mbox_chan *chan) +{ + struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); + u32 val; + + /* Select outbox FIFO mode and reset the outbox FIFO status */ + writel(0x0, priv->outbox_base + SPRD_MBOX_FIFO_RST); + + /* Enable inbox FIFO overflow and delivery interrupt */ + val = readl(priv->inbox_base + SPRD_MBOX_IRQ_MSK); + val &= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ | SPRD_INBOX_FIFO_DELIVER_IRQ); + writel(val, priv->inbox_base + SPRD_MBOX_IRQ_MSK); + + /* Enable outbox FIFO not empty interrupt */ + val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK); + val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ; + writel(val, priv->outbox_base + SPRD_MBOX_IRQ_MSK); + + return 0; +} + +static void sprd_mbox_shutdown(struct mbox_chan *chan) +{ + struct sprd_mbox_priv *priv = to_sprd_mbox_priv(chan->mbox); + + /* Disable inbox & outbox interrupt */ + writel(SPRD_INBOX_FIFO_IRQ_MASK, priv->inbox_base + SPRD_MBOX_IRQ_MSK); + writel(SPRD_OUTBOX_FIFO_IRQ_MASK, priv->outbox_base + SPRD_MBOX_IRQ_MSK); +} + +static const struct mbox_chan_ops sprd_mbox_ops = { + .send_data = sprd_mbox_send_data, + .flush = sprd_mbox_flush, + .startup = sprd_mbox_startup, + .shutdown = sprd_mbox_shutdown, +}; + +static void sprd_mbox_disable(void *data) +{ + struct sprd_mbox_priv *priv = data; + + clk_disable_unprepare(priv->clk); +} + +static int sprd_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sprd_mbox_priv *priv; + int ret, inbox_irq, outbox_irq; + unsigned long id; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + /* + * The Spreadtrum mailbox uses an inbox to send messages to the target + * core, and uses an outbox to receive messages from other cores. + * + * Thus the mailbox controller supplies 2 different register addresses + * and IRQ numbers for inbox and outbox. + */ + priv->inbox_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->inbox_base)) + return PTR_ERR(priv->inbox_base); + + priv->outbox_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(priv->outbox_base)) + return PTR_ERR(priv->outbox_base); + + priv->clk = devm_clk_get(dev, "enable"); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get mailbox clock\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, sprd_mbox_disable, priv); + if (ret) { + dev_err(dev, "failed to add mailbox disable action\n"); + return ret; + } + + inbox_irq = platform_get_irq(pdev, 0); + if (inbox_irq < 0) + return inbox_irq; + + ret = devm_request_irq(dev, inbox_irq, sprd_mbox_inbox_isr, + IRQF_NO_SUSPEND, dev_name(dev), priv); + if (ret) { + dev_err(dev, "failed to request inbox IRQ: %d\n", ret); + return ret; + } + + outbox_irq = platform_get_irq(pdev, 1); + if (outbox_irq < 0) + return outbox_irq; + + ret = devm_request_irq(dev, outbox_irq, sprd_mbox_outbox_isr, + IRQF_NO_SUSPEND, dev_name(dev), priv); + if (ret) { + dev_err(dev, "failed to request outbox IRQ: %d\n", ret); + return ret; + } + + /* Get the default outbox FIFO depth */ + priv->outbox_fifo_depth = + readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1; + priv->mbox.dev = dev; + priv->mbox.chans = &priv->chan[0]; + priv->mbox.num_chans = SPRD_MBOX_CHAN_MAX; + priv->mbox.ops = &sprd_mbox_ops; + priv->mbox.txdone_irq = true; + + for (id = 0; id < SPRD_MBOX_CHAN_MAX; id++) + priv->chan[id].con_priv = (void *)id; + + ret = devm_mbox_controller_register(dev, &priv->mbox); + if (ret) { + dev_err(dev, "failed to register mailbox: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id sprd_mbox_of_match[] = { + { .compatible = "sprd,sc9860-mailbox", }, + { }, +}; +MODULE_DEVICE_TABLE(of, sprd_mbox_of_match); + +static struct platform_driver sprd_mbox_driver = { + .driver = { + .name = "sprd-mailbox", + .of_match_table = sprd_mbox_of_match, + }, + .probe = sprd_mbox_probe, +}; +module_platform_driver(sprd_mbox_driver); + +MODULE_AUTHOR("Baolin Wang "); +MODULE_DESCRIPTION("Spreadtrum mailbox driver"); +MODULE_LICENSE("GPL v2"); From 9d8ca628c0286a35e3f8382e44f8b79846a88603 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 14 Apr 2020 21:21:15 +0800 Subject: [PATCH 08/18] mailbox: imx-mailbox: fix scu msg header size check The i.MX8 SCU message header size is the number of "u32" elements, not "u8", so fix the check. Reported-by: coverity-bot Addresses-Coverity-ID: 1461658 ("Memory - corruptions") Signed-off-by: Peng Fan Reviewed-by: Leonard Crestez Acked-by: Oleksij Rempel Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 19f8d79cebac..bd69ecfb9352 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -155,12 +155,17 @@ static int imx_mu_scu_tx(struct imx_mu_priv *priv, switch (cp->type) { case IMX_MU_TYPE_TX: - if (msg->hdr.size > sizeof(*msg)) { + /* + * msg->hdr.size specifies the number of u32 words while + * sizeof yields bytes. + */ + + if (msg->hdr.size > sizeof(*msg) / 4) { /* * The real message size can be different to * struct imx_sc_rpc_msg_max size */ - dev_err(priv->dev, "Exceed max msg size (%zu) on TX, got: %i\n", sizeof(*msg), msg->hdr.size); + dev_err(priv->dev, "Maximal message size (%zu bytes) exceeded on TX; got: %i bytes\n", sizeof(*msg), msg->hdr.size << 2); return -EINVAL; } @@ -199,9 +204,8 @@ static int imx_mu_scu_rx(struct imx_mu_priv *priv, imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(0)); *data++ = imx_mu_read(priv, priv->dcfg->xRR[0]); - if (msg.hdr.size > sizeof(msg)) { - dev_err(priv->dev, "Exceed max msg size (%zu) on RX, got: %i\n", - sizeof(msg), msg.hdr.size); + if (msg.hdr.size > sizeof(msg) / 4) { + dev_err(priv->dev, "Maximal message size (%zu bytes) exceeded on RX; got: %i bytes\n", sizeof(msg), msg.hdr.size << 2); return -EINVAL; } From 445aeeb569f8d7904f8cf80b7c6826bb651ef80e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 29 Apr 2020 09:35:03 +0000 Subject: [PATCH 09/18] mailbox: zynqmp-ipi: Fix NULL vs IS_ERR() check in zynqmp_ipi_mbox_probe() In case of error, the function devm_ioremap() returns NULL pointer not ERR_PTR(). So we should check whether the return value of devm_ioremap() is NULL instead of IS_ERR. Fixes: 4981b82ba2ff ("mailbox: ZynqMP IPI mailbox controller") Signed-off-by: Wei Yongjun Signed-off-by: Jassi Brar --- drivers/mailbox/zynqmp-ipi-mailbox.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index a4d176f160b8..f44079d62b1a 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -504,10 +504,9 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, mchan->req_buf_size = resource_size(&res); mchan->req_buf = devm_ioremap(mdev, res.start, mchan->req_buf_size); - if (IS_ERR(mchan->req_buf)) { + if (!mchan->req_buf) { dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); - ret = PTR_ERR(mchan->req_buf); - return ret; + return -ENOMEM; } } else if (ret != -ENODEV) { dev_err(mdev, "Unmatched resource %s, %d.\n", name, ret); @@ -520,10 +519,9 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, mchan->resp_buf_size = resource_size(&res); mchan->resp_buf = devm_ioremap(mdev, res.start, mchan->resp_buf_size); - if (IS_ERR(mchan->resp_buf)) { + if (!mchan->resp_buf) { dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); - ret = PTR_ERR(mchan->resp_buf); - return ret; + return -ENOMEM; } } else if (ret != -ENODEV) { dev_err(mdev, "Unmatched resource %s.\n", name); @@ -543,10 +541,9 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, mchan->req_buf_size = resource_size(&res); mchan->req_buf = devm_ioremap(mdev, res.start, mchan->req_buf_size); - if (IS_ERR(mchan->req_buf)) { + if (!mchan->req_buf) { dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); - ret = PTR_ERR(mchan->req_buf); - return ret; + return -ENOMEM; } } else if (ret != -ENODEV) { dev_err(mdev, "Unmatched resource %s.\n", name); @@ -559,10 +556,9 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, mchan->resp_buf_size = resource_size(&res); mchan->resp_buf = devm_ioremap(mdev, res.start, mchan->resp_buf_size); - if (IS_ERR(mchan->resp_buf)) { + if (!mchan->resp_buf) { dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); - ret = PTR_ERR(mchan->resp_buf); - return ret; + return -ENOMEM; } } else if (ret != -ENODEV) { dev_err(mdev, "Unmatched resource %s.\n", name); From a01822e94ee53e8ebc9632fe2764048b81921254 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 20 May 2020 14:18:52 +0530 Subject: [PATCH 10/18] dt-bindings: mailbox: Add devicetree binding for Qcom IPCC Add devicetree YAML binding for Qualcomm Inter-Processor Communication Controller (IPCC) block. Reviewed-by: Bjorn Andersson Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring Signed-off-by: Jassi Brar --- .../bindings/mailbox/qcom-ipcc.yaml | 80 +++++++++++++++++++ include/dt-bindings/mailbox/qcom-ipcc.h | 33 ++++++++ 2 files changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml create mode 100644 include/dt-bindings/mailbox/qcom-ipcc.h diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml new file mode 100644 index 000000000000..4ac2123d9193 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/qcom-ipcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. Inter-Processor Communication Controller + +maintainers: + - Manivannan Sadhasivam + +description: + The Inter-Processor Communication Controller (IPCC) is a centralized hardware + to route interrupts across various subsystems. It involves a three-level + addressing scheme called protocol, client and signal. For example, consider an + entity on the Application Processor Subsystem (APSS) that wants to listen to + Modem's interrupts via Shared Memory Point to Point (SMP2P) interface. In such + a case, the client would be Modem (client-id is 2) and the signal would be + SMP2P (signal-id is 2). The SMP2P itself falls under the Multiprocessor (MPROC) + protocol (protocol-id is 0). Refer include/dt-bindings/mailbox/qcom-ipcc.h + for the list of such IDs. + +properties: + compatible: + items: + - enum: + - qcom,sm8250-ipcc + - const: qcom,ipcc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 3 + description: + The first cell is the client-id, the second cell is the signal-id and the + third cell is the interrupt type. + + "#mbox-cells": + const: 2 + description: + The first cell is the client-id, and the second cell is the signal-id. + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - "#interrupt-cells" + - "#mbox-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + mailbox@408000 { + compatible = "qcom,sm8250-ipcc", "qcom,ipcc"; + reg = <0x408000 0x1000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + + smp2p-modem { + compatible = "qcom,smp2p"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_SMP2P>; + + /* Other SMP2P fields */ + }; diff --git a/include/dt-bindings/mailbox/qcom-ipcc.h b/include/dt-bindings/mailbox/qcom-ipcc.h new file mode 100644 index 000000000000..4c23eefed5f3 --- /dev/null +++ b/include/dt-bindings/mailbox/qcom-ipcc.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __DT_BINDINGS_MAILBOX_IPCC_H +#define __DT_BINDINGS_MAILBOX_IPCC_H + +/* Signal IDs for MPROC protocol */ +#define IPCC_MPROC_SIGNAL_GLINK_QMP 0 +#define IPCC_MPROC_SIGNAL_SMP2P 2 +#define IPCC_MPROC_SIGNAL_PING 3 + +/* Client IDs */ +#define IPCC_CLIENT_AOP 0 +#define IPCC_CLIENT_TZ 1 +#define IPCC_CLIENT_MPSS 2 +#define IPCC_CLIENT_LPASS 3 +#define IPCC_CLIENT_SLPI 4 +#define IPCC_CLIENT_SDC 5 +#define IPCC_CLIENT_CDSP 6 +#define IPCC_CLIENT_NPU 7 +#define IPCC_CLIENT_APSS 8 +#define IPCC_CLIENT_GPU 9 +#define IPCC_CLIENT_CVP 10 +#define IPCC_CLIENT_CAM 11 +#define IPCC_CLIENT_VPU 12 +#define IPCC_CLIENT_PCIE0 13 +#define IPCC_CLIENT_PCIE1 14 +#define IPCC_CLIENT_PCIE2 15 +#define IPCC_CLIENT_SPSS 16 + +#endif From fa74a0257f45c5a92b82ae95c8455f06c598792f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Sat, 30 May 2020 18:15:12 -0500 Subject: [PATCH 11/18] mailbox: Add support for Qualcomm IPCC Add support for the Inter-Processor Communication Controller (IPCC) block from Qualcomm that coordinates the interrupts (inbound & outbound) for Multiprocessor (MPROC), COMPUTE-Level0 (COMPUTE-L0) & COMPUTE-Level1 (COMPUTE-L1) protocols for the Application Processor Subsystem (APSS). This driver is modeled as an irqchip+mailbox driver. The irqchip part helps in receiving the interrupts from the IPCC clients such as modems, DSPs, PCI-E etc... and forwards them to respective entities in APSS. On the other hand, the mailbox part is used to send interrupts to the IPCC clients from the entities of APSS. Reviewed-by: Bjorn Andersson Signed-off-by: Raghavendra Rao Ananta Signed-off-by: Venkata Narendra Kumar Gutta Signed-off-by: Bjorn Andersson [mani: moved to mailbox, added static mbox channels and cleanups] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Jassi Brar --- drivers/mailbox/Kconfig | 10 ++ drivers/mailbox/Makefile | 2 + drivers/mailbox/qcom-ipcc.c | 286 ++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 drivers/mailbox/qcom-ipcc.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index e03f3fb5caed..05b1009e2820 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -244,4 +244,14 @@ config SPRD_MBOX to send message between application processors and MCU. Say Y here if you want to build the Spreatrum mailbox controller driver. +config QCOM_IPCC + bool "Qualcomm Technologies, Inc. IPCC driver" + depends on ARCH_QCOM || COMPILE_TEST + help + Qualcomm Technologies, Inc. Inter-Processor Communication Controller + (IPCC) driver for MSM devices. The driver provides mailbox support for + sending interrupts to the clients. On the other hand, the driver also + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 9caf4ede6ce0..60d224b723a1 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -52,3 +52,5 @@ obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o + +obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c new file mode 100644 index 000000000000..2d13c72944c6 --- /dev/null +++ b/drivers/mailbox/qcom-ipcc.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define IPCC_MBOX_MAX_CHAN 48 + +/* IPCC Register offsets */ +#define IPCC_REG_SEND_ID 0x0c +#define IPCC_REG_RECV_ID 0x10 +#define IPCC_REG_RECV_SIGNAL_ENABLE 0x14 +#define IPCC_REG_RECV_SIGNAL_DISABLE 0x18 +#define IPCC_REG_RECV_SIGNAL_CLEAR 0x1c +#define IPCC_REG_CLIENT_CLEAR 0x38 + +#define IPCC_SIGNAL_ID_MASK GENMASK(15, 0) +#define IPCC_CLIENT_ID_MASK GENMASK(31, 16) + +#define IPCC_NO_PENDING_IRQ GENMASK(31, 0) + +/** + * struct qcom_ipcc_chan_info - Per-mailbox-channel info + * @client_id: The client-id to which the interrupt has to be triggered + * @signal_id: The signal-id to which the interrupt has to be triggered + */ +struct qcom_ipcc_chan_info { + u16 client_id; + u16 signal_id; +}; + +/** + * struct qcom_ipcc - Holder for the mailbox driver + * @dev: Device associated with this instance + * @base: Base address of the IPCC frame associated to APSS + * @irq_domain: The irq_domain associated with this instance + * @chan: The mailbox channels array + * @mchan: The per-mailbox channel info array + * @mbox: The mailbox controller + * @irq: Summary irq + */ +struct qcom_ipcc { + struct device *dev; + void __iomem *base; + struct irq_domain *irq_domain; + struct mbox_chan chan[IPCC_MBOX_MAX_CHAN]; + struct qcom_ipcc_chan_info mchan[IPCC_MBOX_MAX_CHAN]; + struct mbox_controller mbox; + int irq; +}; + +static inline struct qcom_ipcc *to_qcom_ipcc(struct mbox_controller *mbox) +{ + return container_of(mbox, struct qcom_ipcc, mbox); +} + +static inline u32 qcom_ipcc_get_hwirq(u16 client_id, u16 signal_id) +{ + return FIELD_PREP(IPCC_CLIENT_ID_MASK, client_id) | + FIELD_PREP(IPCC_SIGNAL_ID_MASK, signal_id); +} + +static irqreturn_t qcom_ipcc_irq_fn(int irq, void *data) +{ + struct qcom_ipcc *ipcc = data; + u32 hwirq; + int virq; + + for (;;) { + hwirq = readl(ipcc->base + IPCC_REG_RECV_ID); + if (hwirq == IPCC_NO_PENDING_IRQ) + break; + + virq = irq_find_mapping(ipcc->irq_domain, hwirq); + writel(hwirq, ipcc->base + IPCC_REG_RECV_SIGNAL_CLEAR); + generic_handle_irq(virq); + } + + return IRQ_HANDLED; +} + +static void qcom_ipcc_mask_irq(struct irq_data *irqd) +{ + struct qcom_ipcc *ipcc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(hwirq, ipcc->base + IPCC_REG_RECV_SIGNAL_DISABLE); +} + +static void qcom_ipcc_unmask_irq(struct irq_data *irqd) +{ + struct qcom_ipcc *ipcc = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t hwirq = irqd_to_hwirq(irqd); + + writel(hwirq, ipcc->base + IPCC_REG_RECV_SIGNAL_ENABLE); +} + +static struct irq_chip qcom_ipcc_irq_chip = { + .name = "ipcc", + .irq_mask = qcom_ipcc_mask_irq, + .irq_unmask = qcom_ipcc_unmask_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static int qcom_ipcc_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct qcom_ipcc *ipcc = d->host_data; + + irq_set_chip_and_handler(irq, &qcom_ipcc_irq_chip, handle_level_irq); + irq_set_chip_data(irq, ipcc); + irq_set_noprobe(irq); + + return 0; +} + +static int qcom_ipcc_domain_xlate(struct irq_domain *d, + struct device_node *node, const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (intsize != 3) + return -EINVAL; + + *out_hwirq = qcom_ipcc_get_hwirq(intspec[0], intspec[1]); + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static const struct irq_domain_ops qcom_ipcc_irq_ops = { + .map = qcom_ipcc_domain_map, + .xlate = qcom_ipcc_domain_xlate, +}; + +static int qcom_ipcc_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct qcom_ipcc *ipcc = to_qcom_ipcc(chan->mbox); + struct qcom_ipcc_chan_info *mchan = chan->con_priv; + u32 hwirq; + + hwirq = qcom_ipcc_get_hwirq(mchan->client_id, mchan->signal_id); + writel(hwirq, ipcc->base + IPCC_REG_SEND_ID); + + return 0; +} + +static struct mbox_chan *qcom_ipcc_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *ph) +{ + struct qcom_ipcc *ipcc = to_qcom_ipcc(mbox); + struct qcom_ipcc_chan_info *mchan; + struct mbox_chan *chan; + unsigned int i; + + if (ph->args_count != 2) + return ERR_PTR(-EINVAL); + + for (i = 0; i < IPCC_MBOX_MAX_CHAN; i++) { + chan = &ipcc->chan[i]; + if (!chan->con_priv) { + mchan = &ipcc->mchan[i]; + mchan->client_id = ph->args[0]; + mchan->signal_id = ph->args[1]; + chan->con_priv = mchan; + break; + } + + chan = NULL; + } + + return chan ?: ERR_PTR(-EBUSY); +} + +static const struct mbox_chan_ops ipcc_mbox_chan_ops = { + .send_data = qcom_ipcc_mbox_send_data, +}; + +static int qcom_ipcc_setup_mbox(struct qcom_ipcc *ipcc) +{ + struct mbox_controller *mbox; + struct device *dev = ipcc->dev; + + mbox = &ipcc->mbox; + mbox->dev = dev; + mbox->num_chans = IPCC_MBOX_MAX_CHAN; + mbox->chans = ipcc->chan; + mbox->ops = &ipcc_mbox_chan_ops; + mbox->of_xlate = qcom_ipcc_mbox_xlate; + mbox->txdone_irq = false; + mbox->txdone_poll = false; + + return devm_mbox_controller_register(dev, mbox); +} + +static int qcom_ipcc_probe(struct platform_device *pdev) +{ + struct qcom_ipcc *ipcc; + int ret; + + ipcc = devm_kzalloc(&pdev->dev, sizeof(*ipcc), GFP_KERNEL); + if (!ipcc) + return -ENOMEM; + + ipcc->dev = &pdev->dev; + + ipcc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ipcc->base)) + return PTR_ERR(ipcc->base); + + ipcc->irq = platform_get_irq(pdev, 0); + if (ipcc->irq < 0) + return ipcc->irq; + + ipcc->irq_domain = irq_domain_add_tree(pdev->dev.of_node, + &qcom_ipcc_irq_ops, ipcc); + if (!ipcc->irq_domain) + return -ENOMEM; + + ret = qcom_ipcc_setup_mbox(ipcc); + if (ret) + goto err_mbox; + + ret = devm_request_irq(&pdev->dev, ipcc->irq, qcom_ipcc_irq_fn, + IRQF_TRIGGER_HIGH, "ipcc", ipcc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register the irq: %d\n", ret); + goto err_mbox; + } + + enable_irq_wake(ipcc->irq); + platform_set_drvdata(pdev, ipcc); + + return 0; + +err_mbox: + irq_domain_remove(ipcc->irq_domain); + + return ret; +} + +static int qcom_ipcc_remove(struct platform_device *pdev) +{ + struct qcom_ipcc *ipcc = platform_get_drvdata(pdev); + + disable_irq_wake(ipcc->irq); + irq_domain_remove(ipcc->irq_domain); + + return 0; +} + +static const struct of_device_id qcom_ipcc_of_match[] = { + { .compatible = "qcom,ipcc"}, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_ipcc_of_match); + +static struct platform_driver qcom_ipcc_driver = { + .probe = qcom_ipcc_probe, + .remove = qcom_ipcc_remove, + .driver = { + .name = "qcom-ipcc", + .of_match_table = qcom_ipcc_of_match, + }, +}; + +static int __init qcom_ipcc_init(void) +{ + return platform_driver_register(&qcom_ipcc_driver); +} +arch_initcall(qcom_ipcc_init); + +MODULE_AUTHOR("Venkata Narendra Kumar Gutta "); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPCC driver"); +MODULE_LICENSE("GPL v2"); From d61b7997ca467a8249d104f529194a3c6337e767 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 20 May 2020 14:18:54 +0530 Subject: [PATCH 12/18] MAINTAINERS: Add entry for Qualcomm IPCC driver Add MAINTAINERS entry for Qualcomm IPCC driver and its binding. Reviewed-by: Bjorn Andersson Signed-off-by: Manivannan Sadhasivam Signed-off-by: Jassi Brar --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 50659d76976b..ede56ab0fe3c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14030,6 +14030,14 @@ L: linux-arm-msm@vger.kernel.org S: Maintained F: drivers/iommu/qcom_iommu.c +QUALCOMM IPCC MAILBOX DRIVER +M: Manivannan Sadhasivam +L: linux-arm-msm@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +F: drivers/mailbox/qcom-ipcc.c +F: include/dt-bindings/mailbox/qcom-ipcc.h + QUALCOMM RMNET DRIVER M: Subash Abhinov Kasiviswanathan M: Sean Tranchetti From ba5f9fa0ca85a6137fa35efd3a1256d8bb6bc5ff Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 3 Jun 2020 13:15:42 +0800 Subject: [PATCH 13/18] mailbox: imx: Add context save/restore for suspend/resume For "mem" mode suspend on i.MX8 SoCs, MU settings could be lost because its power is off, so save/restore is needed for MU settings during suspend/resume. However, the restore can ONLY be done when MU settings are actually lost, for the scenario of settings NOT lost in "freeze" mode suspend, since there could be still IPC going on multiple CPUs, restoring the MU settings could overwrite the TIE by mistake and cause system freeze, so need to make sure ONLY restore the MU settings when it is powered off, Anson fixes this by checking whether restore is actually needed when resume. Signed-off-by: Dong Aisheng Signed-off-by: Anson Huang Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index bd69ecfb9352..da90a8e1636d 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -67,6 +67,8 @@ struct imx_mu_priv { struct clk *clk; int irq; + u32 xcr; + bool side_b; }; @@ -589,12 +591,45 @@ static const struct of_device_id imx_mu_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_mu_dt_ids); +static int imx_mu_suspend_noirq(struct device *dev) +{ + struct imx_mu_priv *priv = dev_get_drvdata(dev); + + priv->xcr = imx_mu_read(priv, priv->dcfg->xCR); + + return 0; +} + +static int imx_mu_resume_noirq(struct device *dev) +{ + struct imx_mu_priv *priv = dev_get_drvdata(dev); + + /* + * ONLY restore MU when context lost, the TIE could + * be set during noirq resume as there is MU data + * communication going on, and restore the saved + * value will overwrite the TIE and cause MU data + * send failed, may lead to system freeze. This issue + * is observed by testing freeze mode suspend. + */ + if (!imx_mu_read(priv, priv->dcfg->xCR)) + imx_mu_write(priv, priv->xcr, priv->dcfg->xCR); + + return 0; +} + +static const struct dev_pm_ops imx_mu_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_mu_suspend_noirq, + imx_mu_resume_noirq) +}; + static struct platform_driver imx_mu_driver = { .probe = imx_mu_probe, .remove = imx_mu_remove, .driver = { .name = "imx_mu", .of_match_table = imx_mu_dt_ids, + .pm = &imx_mu_pm_ops, }, }; module_platform_driver(imx_mu_driver); From bb2b2624dbe27246bd1ee087f2d50f80daa6622c Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 3 Jun 2020 13:15:43 +0800 Subject: [PATCH 14/18] mailbox: imx: Add runtime PM callback to handle MU clocks Some of i.MX8M SoCs have MU clock, they need to be managed in runtime to make sure the MU clock can be off in runtime, add runtime PM callback to handle MU clock. And on i.MX8MP, the MU clock is combined with power domain and runtime PM is enabled for the clock driver, during noirq suspend/resume phase, runtime PM is disabled by device suspend, but the MU context save/restore needs to enable MU clock for register access, calling clock prepare/enable will trigger runtime resume failure and lead to system suspend failed. Actually, the MU context save/restore is ONLY necessary for SCU IPC MU, other MUs especially on i.MX8MP platforms which have MU clock assigned, they need to runtime request/free mailbox channel in the consumer driver, so no need to save/restore MU context for them, hence it can avoid this issue, so the MU context save/restore is ONLY applied to i.MX platforms MU instance without clock present. Signed-off-by: Anson Huang Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index da90a8e1636d..080b60849e48 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -536,10 +536,13 @@ static int imx_mu_probe(struct platform_device *pdev) if (ret < 0) goto disable_runtime_pm; + clk_disable_unprepare(priv->clk); + return 0; disable_runtime_pm: pm_runtime_disable(dev); + clk_disable_unprepare(priv->clk); return ret; } @@ -547,7 +550,6 @@ static int imx_mu_remove(struct platform_device *pdev) { struct imx_mu_priv *priv = platform_get_drvdata(pdev); - clk_disable_unprepare(priv->clk); pm_runtime_disable(priv->dev); return 0; @@ -595,7 +597,8 @@ static int imx_mu_suspend_noirq(struct device *dev) { struct imx_mu_priv *priv = dev_get_drvdata(dev); - priv->xcr = imx_mu_read(priv, priv->dcfg->xCR); + if (!priv->clk) + priv->xcr = imx_mu_read(priv, priv->dcfg->xCR); return 0; } @@ -612,15 +615,38 @@ static int imx_mu_resume_noirq(struct device *dev) * send failed, may lead to system freeze. This issue * is observed by testing freeze mode suspend. */ - if (!imx_mu_read(priv, priv->dcfg->xCR)) + if (!imx_mu_read(priv, priv->dcfg->xCR) && !priv->clk) imx_mu_write(priv, priv->xcr, priv->dcfg->xCR); return 0; } +static int imx_mu_runtime_suspend(struct device *dev) +{ + struct imx_mu_priv *priv = dev_get_drvdata(dev); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int imx_mu_runtime_resume(struct device *dev) +{ + struct imx_mu_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + dev_err(dev, "failed to enable clock\n"); + + return ret; +} + static const struct dev_pm_ops imx_mu_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_mu_suspend_noirq, imx_mu_resume_noirq) + SET_RUNTIME_PM_OPS(imx_mu_runtime_suspend, + imx_mu_runtime_resume, NULL) }; static struct platform_driver imx_mu_driver = { From b7b2796b9b31e3dcbd563bcf8f983a79bb81163d Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 3 Jun 2020 13:15:44 +0800 Subject: [PATCH 15/18] mailbox: imx: ONLY IPC MU needs IRQF_NO_SUSPEND flag IPC MU has no power domain assigned and there could be IPC during noirq suspend phase, so IRQF_NO_SUSPEND flag is needed for IPC MU. However, for other MUs, they have power domain assigned and their power will be turned off during noirq suspend phase, but with IRQF_NO_SUSPEND set, their interrupts are NOT disabled even after their power turned off, it will cause system crash when mailbox driver trys to handle pending interrupts but the MU power is already turned off. So, IRQF_NO_SUSPEND flag should ONLY be added to IPC MU which has power domain managed by SCU, then all other MUs' pending interrupts after noirq suspend phase will be handled after system resume. Signed-off-by: Anson Huang Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 080b60849e48..7205b825c8b5 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -292,6 +292,7 @@ static int imx_mu_startup(struct mbox_chan *chan) { struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); struct imx_mu_con_priv *cp = chan->con_priv; + unsigned long irq_flag = IRQF_SHARED; int ret; pm_runtime_get_sync(priv->dev); @@ -302,8 +303,12 @@ static int imx_mu_startup(struct mbox_chan *chan) return 0; } - ret = request_irq(priv->irq, imx_mu_isr, IRQF_SHARED | - IRQF_NO_SUSPEND, cp->irq_desc, chan); + /* IPC MU should be with IRQF_NO_SUSPEND set */ + if (!priv->dev->pm_domain) + irq_flag |= IRQF_NO_SUSPEND; + + ret = request_irq(priv->irq, imx_mu_isr, irq_flag, + cp->irq_desc, chan); if (ret) { dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); From f3a1381ec84ec1fdc8091f9935f97e836792b6a7 Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Mon, 8 Jun 2020 15:07:24 +0530 Subject: [PATCH 16/18] dt-bindings: mailbox: Add YAML schemas for QCOM APCS global block Qualcomm APCS global block provides a bunch of generic properties which are required in a device tree. Add YAML schema for these properties. Reviewed-by: Rob Herring Signed-off-by: Sivaprakash Murugesan Signed-off-by: Jassi Brar --- .../mailbox/qcom,apcs-kpss-global.txt | 88 ------------------- .../mailbox/qcom,apcs-kpss-global.yaml | 86 ++++++++++++++++++ 2 files changed, 86 insertions(+), 88 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt create mode 100644 Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt deleted file mode 100644 index beec612dbe6a..000000000000 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt +++ /dev/null @@ -1,88 +0,0 @@ -Binding for the Qualcomm APCS global block -========================================== - -This binding describes the APCS "global" block found in various Qualcomm -platforms. - -- compatible: - Usage: required - Value type: - Definition: must be one of: - "qcom,msm8916-apcs-kpss-global", - "qcom,msm8996-apcs-hmss-global" - "qcom,msm8998-apcs-hmss-global" - "qcom,qcs404-apcs-apps-global" - "qcom,sc7180-apss-shared" - "qcom,sdm845-apss-shared" - "qcom,sm8150-apss-shared" - "qcom,ipq8074-apcs-apps-global" - -- reg: - Usage: required - Value type: - Definition: must specify the base address and size of the global block - -- clocks: - Usage: required if #clock-names property is present - Value type: - Definition: phandles to the two parent clocks of the clock driver. - -- #mbox-cells: - Usage: required - Value type: - Definition: as described in mailbox.txt, must be 1 - -- #clock-cells: - Usage: optional - Value type: - Definition: as described in clock.txt, must be 0 - -- clock-names: - Usage: required if the platform data based clock driver needs to - retrieve the parent clock names from device tree. - This will requires two mandatory clocks to be defined. - Value type: - Definition: must be "pll" and "aux" - -= EXAMPLE -The following example describes the APCS HMSS found in MSM8996 and part of the -GLINK RPM referencing the "rpm_hlos" doorbell therein. - - apcs_glb: mailbox@9820000 { - compatible = "qcom,msm8996-apcs-hmss-global"; - reg = <0x9820000 0x1000>; - - #mbox-cells = <1>; - }; - - rpm-glink { - compatible = "qcom,glink-rpm"; - - interrupts = ; - - qcom,rpm-msg-ram = <&rpm_msg_ram>; - - mboxes = <&apcs_glb 0>; - mbox-names = "rpm_hlos"; - }; - -Below is another example of the APCS binding on MSM8916 platforms: - - apcs: mailbox@b011000 { - compatible = "qcom,msm8916-apcs-kpss-global"; - reg = <0xb011000 0x1000>; - #mbox-cells = <1>; - clocks = <&a53pll>; - #clock-cells = <0>; - }; - -Below is another example of the APCS binding on QCS404 platforms: - - apcs_glb: mailbox@b011000 { - compatible = "qcom,qcs404-apcs-apps-global", "syscon"; - reg = <0x0b011000 0x1000>; - #mbox-cells = <1>; - clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>; - clock-names = "pll", "aux"; - #clock-cells = <0>; - }; diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml new file mode 100644 index 000000000000..12eff942708d --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/mailbox/qcom,apcs-kpss-global.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm APCS global block bindings + +description: + This binding describes the APCS "global" block found in various Qualcomm + platforms. + +maintainers: + - Sivaprakash Murugesan + +properties: + compatible: + enum: + - qcom,ipq8074-apcs-apps-global + - qcom,msm8916-apcs-kpss-global + - qcom,msm8996-apcs-hmss-global + - qcom,msm8998-apcs-hmss-global + - qcom,qcs404-apcs-apps-global + - qcom,sc7180-apss-shared + - qcom,sdm845-apss-shared + - qcom,sm8150-apss-shared + + reg: + maxItems: 1 + + clocks: + description: phandles to the parent clocks of the clock driver + items: + - description: primary pll parent of the clock driver + - description: auxiliary parent + + '#mbox-cells': + const: 1 + + '#clock-cells': + const: 0 + + clock-names: + items: + - const: pll + - const: aux + +required: + - compatible + - reg + - '#mbox-cells' + +additionalProperties: false + +examples: + + # Example apcs with msm8996 + - | + #include + apcs_glb: mailbox@9820000 { + compatible = "qcom,msm8996-apcs-hmss-global"; + reg = <0x9820000 0x1000>; + + #mbox-cells = <1>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + mbox-names = "rpm_hlos"; + }; + + # Example apcs with qcs404 + - | + #define GCC_APSS_AHB_CLK_SRC 1 + #define GCC_GPLL0_AO_OUT_MAIN 123 + apcs: mailbox@b011000 { + compatible = "qcom,qcs404-apcs-apps-global"; + reg = <0x0b011000 0x1000>; + #mbox-cells = <1>; + clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>; + clock-names = "pll", "aux"; + #clock-cells = <0>; + }; From 9b007938ae3cd75d0ae883c6c0eeb0985cacba15 Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Mon, 8 Jun 2020 15:07:26 +0530 Subject: [PATCH 17/18] mailbox: qcom: Add clock driver name in apcs mailbox driver data Some apcs mailbox devices supports a clock driver, the compatible strings of devices supporting clock driver along with the clock driver name are maintained in a separate structure within the mailbox driver. And the clock driver is added based on device match. With increase in number of devices supporting the clock feature move the clock driver name inside the driver data. so that we can use a single API to get the register offset of mailbox driver and clock driver name together, and the clock driver will be added based on the driver data. Signed-off-by: Sivaprakash Murugesan Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 56 +++++++++++++++++-------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index eeebafd546e5..49eebb5b87bc 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -24,6 +24,31 @@ struct qcom_apcs_ipc { struct platform_device *clk; }; +struct qcom_apcs_ipc_data { + int offset; + char *clk_name; +}; + +static const struct qcom_apcs_ipc_data ipq8074_apcs_data = { + .offset = 8, .clk_name = NULL +}; + +static const struct qcom_apcs_ipc_data msm8916_apcs_data = { + .offset = 8, .clk_name = "qcom-apcs-msm8916-clk" +}; + +static const struct qcom_apcs_ipc_data msm8996_apcs_data = { + .offset = 16, .clk_name = NULL +}; + +static const struct qcom_apcs_ipc_data msm8998_apcs_data = { + .offset = 8, .clk_name = NULL +}; + +static const struct qcom_apcs_ipc_data apps_shared_apcs_data = { + .offset = 12, .clk_name = NULL +}; + static const struct regmap_config apcs_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -48,17 +73,12 @@ static const struct mbox_chan_ops qcom_apcs_ipc_ops = { static int qcom_apcs_ipc_probe(struct platform_device *pdev) { struct qcom_apcs_ipc *apcs; + const struct qcom_apcs_ipc_data *apcs_data; struct regmap *regmap; struct resource *res; - unsigned long offset; void __iomem *base; unsigned long i; int ret; - const struct of_device_id apcs_clk_match_table[] = { - { .compatible = "qcom,msm8916-apcs-kpss-global", }, - { .compatible = "qcom,qcs404-apcs-apps-global", }, - {} - }; apcs = devm_kzalloc(&pdev->dev, sizeof(*apcs), GFP_KERNEL); if (!apcs) @@ -73,10 +93,10 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - offset = (unsigned long)of_device_get_match_data(&pdev->dev); + apcs_data = of_device_get_match_data(&pdev->dev); apcs->regmap = regmap; - apcs->offset = offset; + apcs->offset = apcs_data->offset; /* Initialize channel identifiers */ for (i = 0; i < ARRAY_SIZE(apcs->mbox_chans); i++) @@ -93,9 +113,9 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev) return ret; } - if (of_match_device(apcs_clk_match_table, &pdev->dev)) { + if (apcs_data->clk_name) { apcs->clk = platform_device_register_data(&pdev->dev, - "qcom-apcs-msm8916-clk", + apcs_data->clk_name, PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(apcs->clk)) @@ -119,14 +139,14 @@ static int qcom_apcs_ipc_remove(struct platform_device *pdev) /* .data is the offset of the ipc register within the global block */ static const struct of_device_id qcom_apcs_ipc_of_match[] = { - { .compatible = "qcom,msm8916-apcs-kpss-global", .data = (void *)8 }, - { .compatible = "qcom,msm8996-apcs-hmss-global", .data = (void *)16 }, - { .compatible = "qcom,msm8998-apcs-hmss-global", .data = (void *)8 }, - { .compatible = "qcom,qcs404-apcs-apps-global", .data = (void *)8 }, - { .compatible = "qcom,sc7180-apss-shared", .data = (void *)12 }, - { .compatible = "qcom,sdm845-apss-shared", .data = (void *)12 }, - { .compatible = "qcom,sm8150-apss-shared", .data = (void *)12 }, - { .compatible = "qcom,ipq8074-apcs-apps-global", .data = (void *)8 }, + { .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq8074_apcs_data }, + { .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data }, + { .compatible = "qcom,msm8996-apcs-hmss-global", .data = &msm8996_apcs_data }, + { .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8998_apcs_data }, + { .compatible = "qcom,qcs404-apcs-apps-global", .data = &msm8916_apcs_data }, + { .compatible = "qcom,sc7180-apss-shared", .data = &apps_shared_apcs_data }, + { .compatible = "qcom,sdm845-apss-shared", .data = &apps_shared_apcs_data }, + { .compatible = "qcom,sm8150-apss-shared", .data = &apps_shared_apcs_data }, {} }; MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match); From e9f901dc05c09c4f89183cadcb2d93177f3100cb Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Mon, 8 Jun 2020 15:07:27 +0530 Subject: [PATCH 18/18] mailbox: qcom: Add ipq6018 apcs compatible The Qualcomm ipq6018 has apcs block, add compatible for the same. Also, the ipq6018 apcs provides a clock functionality similar to msm8916 but the clock driver is different. Create a child device based on the apcs compatible for the clock controller functionality. Signed-off-by: Sivaprakash Murugesan Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index 49eebb5b87bc..cec34f0af6ce 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -29,6 +29,10 @@ struct qcom_apcs_ipc_data { char *clk_name; }; +static const struct qcom_apcs_ipc_data ipq6018_apcs_data = { + .offset = 8, .clk_name = "qcom,apss-ipq6018-clk" +}; + static const struct qcom_apcs_ipc_data ipq8074_apcs_data = { .offset = 8, .clk_name = NULL }; @@ -139,6 +143,7 @@ static int qcom_apcs_ipc_remove(struct platform_device *pdev) /* .data is the offset of the ipc register within the global block */ static const struct of_device_id qcom_apcs_ipc_of_match[] = { + { .compatible = "qcom,ipq6018-apcs-apps-global", .data = &ipq6018_apcs_data }, { .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq8074_apcs_data }, { .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data }, { .compatible = "qcom,msm8996-apcs-hmss-global", .data = &msm8996_apcs_data },