From patchwork Tue May 2 13:55:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 98447 Delivered-To: patch@linaro.org Received: by 10.140.109.52 with SMTP id k49csp1885456qgf; Tue, 2 May 2017 06:56:59 -0700 (PDT) X-Received: by 10.99.104.9 with SMTP id d9mr33493308pgc.27.1493733419098; Tue, 02 May 2017 06:56:59 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l2si5406930pln.183.2017.05.02.06.56.58; Tue, 02 May 2017 06:56:59 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751697AbdEBN4q (ORCPT + 25 others); Tue, 2 May 2017 09:56:46 -0400 Received: from foss.arm.com ([217.140.101.70]:44806 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751442AbdEBN4G (ORCPT ); Tue, 2 May 2017 09:56:06 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 20CDD2B; Tue, 2 May 2017 06:56:06 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3CDBF3F23B; Tue, 2 May 2017 06:56:05 -0700 (PDT) From: Sudeep Holla To: linux-kernel@vger.kernel.org, Jassi Brar Cc: Sudeep Holla , Alexey Klimov , Jassi Brar Subject: [PATCH 5/6] mailbox: arm_mhu: add full support for sub-channels Date: Tue, 2 May 2017 14:55:52 +0100 Message-Id: <1493733353-25812-6-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1493733353-25812-1-git-send-email-sudeep.holla@arm.com> References: <1493733353-25812-1-git-send-email-sudeep.holla@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We now have the basic infrastructure and binding to support subchannels on ARM MHU controller. This patch adds all the necessary mailbox operations to add support for the sub-channels. Maximum of 32 subchannels are supported on each physical channel, however the total number of subchannels is restricted to 20 in order to save memory. It can increased if required in future. Cc: Alexey Klimov Cc: Jassi Brar Signed-off-by: Sudeep Holla --- drivers/mailbox/arm_mhu.c | 127 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 4 deletions(-) -- 2.7.4 diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index 4e0f690b97fd..0f5ab2204649 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,14 @@ mhu_mbox_to_channel(struct mbox_controller *mbox, return NULL; } +static void mhu_mbox_clear_irq(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].rx_reg; + + writel_relaxed(BIT(chan_info->subchan), base + INTR_CLR_OFS); +} + static unsigned int mhu_mbox_irq_to_pchan_num(struct arm_mhu *mhu, int irq) { unsigned int pchan; @@ -105,6 +114,95 @@ static unsigned int mhu_mbox_irq_to_pchan_num(struct arm_mhu *mhu, int irq) return pchan; } +static struct mbox_chan *mhu_mbox_irq_to_channel(struct arm_mhu *mhu, + unsigned int pchan) +{ + unsigned long bits; + unsigned int subchan; + struct mbox_chan *chan = NULL; + struct mbox_controller *mbox = &mhu->mbox; + void __iomem *base = mhu->mlink[pchan].rx_reg; + + bits = readl_relaxed(base + INTR_STAT_OFS); + if (!bits) + /* No IRQs fired in specified physical channel */ + return NULL; + + /* An IRQ has fired, find the associated channel */ + for (subchan = 0; bits; subchan++) { + if (!test_and_clear_bit(subchan, &bits)) + continue; + + chan = mhu_mbox_to_channel(mbox, pchan, subchan); + if (chan) + break; + } + + return chan; +} + +static irqreturn_t mhu_mbox_thread_handler(int irq, void *data) +{ + struct mbox_chan *chan; + struct arm_mhu *mhu = data; + unsigned int pchan = mhu_mbox_irq_to_pchan_num(mhu, irq); + + while (NULL != (chan = mhu_mbox_irq_to_channel(mhu, pchan))) { + mbox_chan_received_data(chan, NULL); + mhu_mbox_clear_irq(chan); + } + + return IRQ_HANDLED; +} + +static bool mhu_subchan_last_tx_done(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; + + if (readl_relaxed(base + INTR_STAT_OFS) & BIT(chan_info->subchan)) + return false; + + return true; +} + +static int mhu_subchan_send_data(struct mbox_chan *chan, void *data) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; + + /* Send event to co-processor */ + writel_relaxed(BIT(chan_info->subchan), base + INTR_SET_OFS); + + return 0; +} + +static int mhu_subchan_startup(struct mbox_chan *chan) +{ + mhu_mbox_clear_irq(chan); + return 0; +} + +static void mhu_subchan_shutdown(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + struct mbox_controller *mbox = &chan_info->mhu->mbox; + int i; + + for (i = 0; i < mbox->num_chans; i++) + if (chan == &mbox->chans[i]) + break; + + if (mbox->num_chans == i) { + dev_warn(mbox->dev, "Request to free non-existent channel\n"); + return; + } + + /* Reset channel */ + mhu_mbox_clear_irq(chan); + chan->con_priv = NULL; +} + static struct mbox_chan *mhu_mbox_xlate(struct mbox_controller *mbox, const struct of_phandle_args *spec) { @@ -227,14 +325,28 @@ static const struct mbox_chan_ops mhu_ops = { .last_tx_done = mhu_last_tx_done, }; +static const struct mbox_chan_ops mhu_subchan_ops = { + .send_data = mhu_subchan_send_data, + .startup = mhu_subchan_startup, + .shutdown = mhu_subchan_shutdown, + .last_tx_done = mhu_subchan_last_tx_done, +}; + static const struct mhu_mbox_pdata arm_mhu_pdata = { .num_pchans = 3, .num_subchans = 1, .support_subchans = false, }; +static const struct mhu_mbox_pdata arm_mhu_v2_pdata = { + .num_pchans = 2, /* Secure can't be used */ + .num_subchans = 32, + .support_subchans = true, +}; + static const struct of_device_id mhu_mbox_match[] = { { .compatible = "arm,mhu", .data = (void *)&arm_mhu_pdata }, + { .compatible = "arm,mhu-v2", .data = (void *)&arm_mhu_v2_pdata }, {} }; @@ -243,6 +355,7 @@ MODULE_DEVICE_TABLE(of, mhu_mbox_match); static int mhu_probe(struct amba_device *adev, const struct amba_id *id) { int i, err, max_chans; + irq_handler_t handler; struct arm_mhu *mhu; struct mbox_chan *chans; struct mhu_mbox_pdata *pdata; @@ -287,7 +400,6 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) mhu->mbox.dev = dev; mhu->mbox.chans = chans; mhu->mbox.num_chans = max_chans; - mhu->mbox.ops = &mhu_ops; mhu->mbox.txdone_irq = false; mhu->mbox.txdone_poll = true; mhu->mbox.txpoll_period = 1; @@ -295,6 +407,14 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) mhu->mbox.of_xlate = mhu_mbox_xlate; amba_set_drvdata(adev, mhu); + if (pdata->support_subchans) { + mhu->mbox.ops = &mhu_subchan_ops; + handler = mhu_mbox_thread_handler; + } else { + mhu->mbox.ops = &mhu_ops; + handler = mhu_rx_interrupt; + } + err = mbox_controller_register(&mhu->mbox); if (err) { dev_err(dev, "Failed to register mailboxes %d\n", err); @@ -312,9 +432,8 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; - err = devm_request_threaded_irq(dev, irq, NULL, - mhu_rx_interrupt, IRQF_ONESHOT, - "mhu_link", mhu); + err = devm_request_threaded_irq(dev, irq, NULL, handler, + IRQF_ONESHOT, "mhu_link", mhu); if (err) { dev_err(dev, "Can't claim IRQ %d\n", irq); mbox_controller_unregister(&mhu->mbox);