From patchwork Mon May 6 07:24:23 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jassi Brar X-Patchwork-Id: 2523251 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 65090DF230 for ; Mon, 6 May 2013 07:26:59 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UZFoI-0003AL-7M; Mon, 06 May 2013 07:26:12 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UZFnh-00080A-Aw; Mon, 06 May 2013 07:25:33 +0000 Received: from mail-pb0-x22d.google.com ([2607:f8b0:400e:c01::22d]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UZFnd-0007yA-Tw for linux-arm-kernel@lists.infradead.org; Mon, 06 May 2013 07:25:31 +0000 Received: by mail-pb0-f45.google.com with SMTP id ro12so1840425pbb.18 for ; Mon, 06 May 2013 00:25:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=TUPfZTzWRys6e5exzlfzeW9bMcK2Sh6x5hjbw+ojx/g=; b=obzOe4AWIIruj16ovMA7OMW9vFp7t1u1/YHtDNZfzUk5K5PQ0fV6Qj1pwpeMH5EneI 3lNyN+8yT/5f4zSZeI8tsyxZNhiYbsJfRAfeVHARQzhg2XtVvdjFH4/FtK09VNyie813 /27ihaO6+LkCS7SL5cDnpmo8Lwb9Umi31/KVuFGUQxOVf+Ls/ouWKSeuGnVfA2nvxjib DSfq/V50AARmS3mghyZ40NgU1qqGcpHPGf7J9KpPl6l//zDS4oHsZfdk8yWmLkIigGUj x9gFldwi4Dsa3Mlcviua1KrNarvXzUOnGJXJQ33JSJMNS9A9TZpEsA+5DXhgkO9meOQM RwOA== X-Received: by 10.68.202.34 with SMTP id kf2mr14320174pbc.56.1367825108399; Mon, 06 May 2013 00:25:08 -0700 (PDT) Received: from localhost.localdomain ([117.212.48.250]) by mx.google.com with ESMTPSA id sg4sm22828419pbc.7.2013.05.06.00.25.04 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 06 May 2013 00:25:08 -0700 (PDT) From: Jassi Brar To: s-anna@ti.com, loic.pallardy@st.com Subject: [PATCHv2 3/4] mailbox: pl320: Introduce common API driver Date: Mon, 6 May 2013 12:54:23 +0530 Message-Id: <1367825063-6263-1-git-send-email-jaswinder.singh@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1367824946-6160-1-git-send-email-jaswinder.singh@linaro.org> References: <1367824946-6160-1-git-send-email-jaswinder.singh@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130506_032530_152199_2461DA27 X-CRM114-Status: GOOD ( 29.95 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (jassisinghbrar[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: linux-arm-kernel@lists.infradead.org, Jassi Brar , linux-kernel@vger.kernel.org, arnd@arndb.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Convert the PL320 controller driver to work with the common mailbox API. Also convert the only user of PL320, highbank-cpufreq.c to work with thee API. Drop the obsoleted driver pl320-ipc.c Signed-off-by: Jassi Brar --- drivers/cpufreq/highbank-cpufreq.c | 22 +++- drivers/mailbox/Makefile | 2 +- drivers/mailbox/pl320-ipc.c | 198 --------------------------------- drivers/mailbox/pl320.c | 212 ++++++++++++++++++++++++++++++++++++ include/linux/pl320-ipc.h | 17 --- 5 files changed, 233 insertions(+), 218 deletions(-) delete mode 100644 drivers/mailbox/pl320-ipc.c create mode 100644 drivers/mailbox/pl320.c delete mode 100644 include/linux/pl320-ipc.h diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index 3118b87..5c057e0 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #define HB_CPUFREQ_CHANGE_NOTE 0x80000001 @@ -29,8 +29,26 @@ static int hb_voltage_change(unsigned int freq) { u32 msg[HB_CPUFREQ_IPC_LEN] = {HB_CPUFREQ_CHANGE_NOTE, freq / 1000000}; + struct ipc_client cl; + int ret = -ETIMEDOUT; + void *chan; - return pl320_ipc_transmit(msg); + cl.rxcb = NULL; + cl.txcb = NULL; + cl.tx_block = true; + cl.tx_tout = 1000; /* 1 sec */ + cl.cntlr_data = NULL; + cl.knows_txdone = false; + cl.chan_name = "pl320:A9_to_M3"; + + chan = ipc_request_channel(&cl); + + if (ipc_send_message(chan, (void *)msg)) + ret = msg[1]; /* PL320 updates buffer with FIFO after ACK */ + + ipc_free_channel(chan); + + return ret; } static int hb_cpufreq_clk_notify(struct notifier_block *nb, diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fefef7e..7b897f3 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_MAILBOX) += mailbox.o -obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o +obj-$(CONFIG_PL320_MBOX) += pl320.o diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c deleted file mode 100644 index f3755e0..0000000 --- a/drivers/mailbox/pl320-ipc.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2012 Calxeda, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define IPCMxSOURCE(m) ((m) * 0x40) -#define IPCMxDSET(m) (((m) * 0x40) + 0x004) -#define IPCMxDCLEAR(m) (((m) * 0x40) + 0x008) -#define IPCMxDSTATUS(m) (((m) * 0x40) + 0x00C) -#define IPCMxMODE(m) (((m) * 0x40) + 0x010) -#define IPCMxMSET(m) (((m) * 0x40) + 0x014) -#define IPCMxMCLEAR(m) (((m) * 0x40) + 0x018) -#define IPCMxMSTATUS(m) (((m) * 0x40) + 0x01C) -#define IPCMxSEND(m) (((m) * 0x40) + 0x020) -#define IPCMxDR(m, dr) (((m) * 0x40) + ((dr) * 4) + 0x024) - -#define IPCMMIS(irq) (((irq) * 8) + 0x800) -#define IPCMRIS(irq) (((irq) * 8) + 0x804) - -#define MBOX_MASK(n) (1 << (n)) -#define IPC_TX_MBOX 1 -#define IPC_RX_MBOX 2 - -#define CHAN_MASK(n) (1 << (n)) -#define A9_SOURCE 1 -#define M3_SOURCE 0 - -static void __iomem *ipc_base; -static int ipc_irq; -static DEFINE_MUTEX(ipc_m1_lock); -static DECLARE_COMPLETION(ipc_completion); -static ATOMIC_NOTIFIER_HEAD(ipc_notifier); - -static inline void set_destination(int source, int mbox) -{ - __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox)); - __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox)); -} - -static inline void clear_destination(int source, int mbox) -{ - __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox)); - __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox)); -} - -static void __ipc_send(int mbox, u32 *data) -{ - int i; - for (i = 0; i < 7; i++) - __raw_writel(data[i], ipc_base + IPCMxDR(mbox, i)); - __raw_writel(0x1, ipc_base + IPCMxSEND(mbox)); -} - -static u32 __ipc_rcv(int mbox, u32 *data) -{ - int i; - for (i = 0; i < 7; i++) - data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i)); - return data[1]; -} - -/* blocking implmentation from the A9 side, not usuable in interrupts! */ -int pl320_ipc_transmit(u32 *data) -{ - int ret; - - mutex_lock(&ipc_m1_lock); - - init_completion(&ipc_completion); - __ipc_send(IPC_TX_MBOX, data); - ret = wait_for_completion_timeout(&ipc_completion, - msecs_to_jiffies(1000)); - if (ret == 0) { - ret = -ETIMEDOUT; - goto out; - } - - ret = __ipc_rcv(IPC_TX_MBOX, data); -out: - mutex_unlock(&ipc_m1_lock); - return ret; -} -EXPORT_SYMBOL_GPL(pl320_ipc_transmit); - -static irqreturn_t ipc_handler(int irq, void *dev) -{ - u32 irq_stat; - u32 data[7]; - - irq_stat = __raw_readl(ipc_base + IPCMMIS(1)); - if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) { - __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX)); - complete(&ipc_completion); - } - if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) { - __ipc_rcv(IPC_RX_MBOX, data); - atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1); - __raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX)); - } - - return IRQ_HANDLED; -} - -int pl320_ipc_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&ipc_notifier, nb); -} -EXPORT_SYMBOL_GPL(pl320_ipc_register_notifier); - -int pl320_ipc_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&ipc_notifier, nb); -} -EXPORT_SYMBOL_GPL(pl320_ipc_unregister_notifier); - -static int pl320_probe(struct amba_device *adev, const struct amba_id *id) -{ - int ret; - - ipc_base = ioremap(adev->res.start, resource_size(&adev->res)); - if (ipc_base == NULL) - return -ENOMEM; - - __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX)); - - ipc_irq = adev->irq[0]; - ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL); - if (ret < 0) - goto err; - - /* Init slow mailbox */ - __raw_writel(CHAN_MASK(A9_SOURCE), - ipc_base + IPCMxSOURCE(IPC_TX_MBOX)); - __raw_writel(CHAN_MASK(M3_SOURCE), - ipc_base + IPCMxDSET(IPC_TX_MBOX)); - __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE), - ipc_base + IPCMxMSET(IPC_TX_MBOX)); - - /* Init receive mailbox */ - __raw_writel(CHAN_MASK(M3_SOURCE), - ipc_base + IPCMxSOURCE(IPC_RX_MBOX)); - __raw_writel(CHAN_MASK(A9_SOURCE), - ipc_base + IPCMxDSET(IPC_RX_MBOX)); - __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE), - ipc_base + IPCMxMSET(IPC_RX_MBOX)); - - return 0; -err: - iounmap(ipc_base); - return ret; -} - -static struct amba_id pl320_ids[] = { - { - .id = 0x00041320, - .mask = 0x000fffff, - }, - { 0, 0 }, -}; - -static struct amba_driver pl320_driver = { - .drv = { - .name = "pl320", - }, - .id_table = pl320_ids, - .probe = pl320_probe, -}; - -static int __init ipc_init(void) -{ - return amba_driver_register(&pl320_driver); -} -module_init(ipc_init); diff --git a/drivers/mailbox/pl320.c b/drivers/mailbox/pl320.c new file mode 100644 index 0000000..7ddae5c --- /dev/null +++ b/drivers/mailbox/pl320.c @@ -0,0 +1,212 @@ +/* + * Copyright 2012 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPCMSOURCE(m) ((m) * 0x40) +#define IPCMDSET(m) (((m) * 0x40) + 0x004) +#define IPCMDCLEAR(m) (((m) * 0x40) + 0x008) +#define IPCMDSTATUS(m) (((m) * 0x40) + 0x00C) +#define IPCMMODE(m) (((m) * 0x40) + 0x010) +#define IPCMMSET(m) (((m) * 0x40) + 0x014) +#define IPCMMCLEAR(m) (((m) * 0x40) + 0x018) +#define IPCMMSTATUS(m) (((m) * 0x40) + 0x01C) +#define IPCMSEND(m) (((m) * 0x40) + 0x020) +#define IPCMDR(m, dr) (((m) * 0x40) + ((dr) * 4) + 0x024) + +#define IPCMMIS(irq) (((irq) * 8) + 0x800) +#define IPCMRIS(irq) (((irq) * 8) + 0x804) + +#define MBOX_MASK(n) (1 << (n)) +#define IPC_TX_MBOX 1 + +#define CHAN_MASK(n) (1 << (n)) +#define A9_SOURCE 1 +#define M3_SOURCE 0 + +struct pl320_con { + u32 *data; + int ipc_irq; + struct device *dev; + struct ipc_link link; + void __iomem *ipc_base; + struct ipc_controller ipc_con; +}; + +static inline struct pl320_con *to_pl320(struct ipc_link *l) +{ + if (!l) + return NULL; + + return container_of(l, struct pl320_con, link); +} + +static irqreturn_t ipc_handler(int irq, void *p) +{ + struct ipc_link *link = (struct ipc_link *)p; + struct pl320_con *pl320 = to_pl320(link); + void __iomem *ipc_base = pl320->ipc_base; + u32 irq_stat; + + irq_stat = __raw_readl(ipc_base + IPCMMIS(1)); + if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) { + u32 *data = pl320->data; + int i; + + __raw_writel(0, ipc_base + IPCMSEND(IPC_TX_MBOX)); + + /* + * The PL320 driver specifies that the send buffer + * will be overwritten by same fifo upon TX ACK. + */ + for (i = 0; i < 7; i++) + data[i] = __raw_readl(ipc_base + + IPCMDR(IPC_TX_MBOX, i)); + + ipc_link_txdone(link, XFER_OK); + + pl320->data = NULL; + } + + return IRQ_HANDLED; +} + +static int pl320_send_data(struct ipc_link *link, void *msg) +{ + struct pl320_con *pl320 = to_pl320(link); + void __iomem *ipc_base = pl320->ipc_base; + u32 *data = (u32 *)msg; + int i; + + pl320->data = data; + + for (i = 0; i < 7; i++) + __raw_writel(data[i], ipc_base + IPCMDR(IPC_TX_MBOX, i)); + + __raw_writel(0x1, ipc_base + IPCMSEND(IPC_TX_MBOX)); + + return 0; +} + +static int pl320_startup(struct ipc_link *link, void *ignored) +{ + struct pl320_con *pl320 = to_pl320(link); + void __iomem *ipc_base = pl320->ipc_base; + int err, ipc_irq = pl320->ipc_irq; + + __raw_writel(0, ipc_base + IPCMSEND(IPC_TX_MBOX)); + + err = request_irq(ipc_irq, ipc_handler, 0, dev_name(pl320->dev), link); + if (err) + return err; + + /* Init slow mailbox */ + __raw_writel(CHAN_MASK(A9_SOURCE), + ipc_base + IPCMSOURCE(IPC_TX_MBOX)); + __raw_writel(CHAN_MASK(M3_SOURCE), + ipc_base + IPCMDSET(IPC_TX_MBOX)); + __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE), + ipc_base + IPCMMSET(IPC_TX_MBOX)); + + pl320->data = NULL; + return 0; +} + +static void pl320_shutdown(struct ipc_link *link) +{ + struct pl320_con *pl320 = to_pl320(link); + + pl320->data = NULL; + free_irq(pl320->ipc_irq, link); +} + +static struct ipc_link_ops pl320_ops = { + .send_data = pl320_send_data, + .startup = pl320_startup, + .shutdown = pl320_shutdown, +}; + +static int pl320_probe(struct amba_device *adev, const struct amba_id *id) +{ + struct pl320_con *pl320; + struct ipc_link *l[2]; + int ret; + + pl320 = kzalloc(sizeof(struct pl320_con), GFP_KERNEL); + if (!pl320) + return -ENOMEM; + + pl320->ipc_base = ioremap(adev->res.start, resource_size(&adev->res)); + if (pl320->ipc_base == NULL) { + kfree(pl320); + return -ENOMEM; + } + + pl320->dev = &adev->dev; + pl320->ipc_irq = adev->irq[0]; + amba_set_drvdata(adev, pl320); + + l[0] = &pl320->link; + l[1] = NULL; + pl320->ipc_con.links = l; + pl320->ipc_con.txdone_irq = true; + pl320->ipc_con.ops = &pl320_ops; + snprintf(pl320->link.link_name, 16, "A9_to_M3"); + snprintf(pl320->ipc_con.controller_name, 16, "pl320"); + + ret = ipc_links_register(&pl320->ipc_con); + if (ret) { + iounmap(pl320->ipc_base); + kfree(pl320); + } + + return ret; +} + +static struct amba_id pl320_ids[] = { + { + .id = 0x00041320, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver pl320_driver = { + .drv = { + .name = "pl320", + }, + .id_table = pl320_ids, + .probe = pl320_probe, +}; + +static int __init ipc_init(void) +{ + return amba_driver_register(&pl320_driver); +} +module_init(ipc_init); diff --git a/include/linux/pl320-ipc.h b/include/linux/pl320-ipc.h deleted file mode 100644 index 5161f63..0000000 --- a/include/linux/pl320-ipc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -int pl320_ipc_transmit(u32 *data); -int pl320_ipc_register_notifier(struct notifier_block *nb); -int pl320_ipc_unregister_notifier(struct notifier_block *nb);