From patchwork Tue Nov 6 02:55:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omar Ramirez Luna X-Patchwork-Id: 1702531 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 208F4DF2AB for ; Tue, 6 Nov 2012 02:56:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964828Ab2KFC4W (ORCPT ); Mon, 5 Nov 2012 21:56:22 -0500 Received: from mail-oa0-f46.google.com ([209.85.219.46]:51678 "EHLO mail-oa0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964824Ab2KFC4S (ORCPT ); Mon, 5 Nov 2012 21:56:18 -0500 Received: by mail-oa0-f46.google.com with SMTP id h16so6546346oag.19 for ; Mon, 05 Nov 2012 18:56:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=ZWGo+5mt09aPbQb1rbwVik/TUO4fcn8fZHkUSGTp3jQ=; b=Nkl1T8ACtYuu3MBLGQyYge6j6DErbjrxhzJljnEtD2huUQ0svZorVzG09bG9M5eMo5 BePT0fArc5YsgyACv3OFIeO0CToJw6qshv6bFztLpzTSaE+lwmgl+3DNcWCmgolnAFeg y0j/+eDrGg7vZvzZxL4Ojm/lGVSRBWz/QOSLQQxg3YzpcuTphoSO9pxSFvooYgrVpyH6 b2MPXBTWikygl/P/8fJheYlI7L9DItQ15ZDaexgn+b/ruK/jKQbSrIsrct37855UtETQ N6B7CbBY/011TsJ6+CVcJkFc9V2PyPojSQIIvIamFJkWkGq6PsCwtX8rkng3b1dXZlsy QjYw== Received: by 10.60.170.110 with SMTP id al14mr9356126oec.120.1352170576637; Mon, 05 Nov 2012 18:56:16 -0800 (PST) Received: from uda0273944.am.dhcp.ti.com (dragon.ti.com. [192.94.94.33]) by mx.google.com with ESMTPS id b5sm19544680obd.18.2012.11.05.18.56.15 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 05 Nov 2012 18:56:15 -0800 (PST) From: Omar Ramirez Luna To: Greg Kroah-Hartman Cc: Russell King , Tony Lindgren , Janusz Krzysztofik , Omar Ramirez Luna , Loic PALLARDY , Arnd Bergmann , Ohad Ben-Cohen , Mark Brown , Dom Cobley , Wim Van Sebroeck , Linus Walleij , Suman Anna , Juan Gutierrez , Felipe Contreras , Tejun Heo , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org Subject: [PATCH v2 1/2] mailbox: OMAP: introduce mailbox framework Date: Mon, 5 Nov 2012 20:55:51 -0600 Message-Id: <1352170552-29564-2-git-send-email-omar.luna@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1352170552-29564-1-git-send-email-omar.luna@linaro.org> References: <1352170552-29564-1-git-send-email-omar.luna@linaro.org> X-Gm-Message-State: ALoCoQml9H9CXARWQhICmeObw4wp3oPKzZnNxjgwzYC//+VKH6EHa6BcKvQAgZjTORrnX6rADkNX Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org Actually moving it from plat-omap, as this framework/driver code is supposed to be under drivers/ folder. The framework should work with the current supported OMAP processors (OMAP1+) that have mailbox and can be used as a method of interprocessor communication. The mailbox hardware (in OMAP) uses a queued mailbox-interrupt mechanism that provides a communication channel between processors through a set of registers and their associated interrupt signals by sending and receiving messages. As part of the migration from plat and mach code: - Kconfig symbols have been renamed to build OMAP1 or OMAP2+ drivers. - mailbox.h has been changed from plat to a dedicated drivers/ folder. - soc.h has been changed for plat/cpu.h, since there are dependencies in the cpu_is_XXXX() macro. Module names have changed too, instead of mailbox_mach: - OMAP1: mailbox-omap1.ko - OMAP2+: mailbox-omap2.ko Signed-off-by: Omar Ramirez Luna --- arch/arm/configs/omap1_defconfig | 3 +- arch/arm/mach-omap1/Makefile | 4 - arch/arm/mach-omap1/mailbox.c | 199 ------------- arch/arm/mach-omap2/Makefile | 3 - arch/arm/mach-omap2/devices.c | 4 +- arch/arm/mach-omap2/mailbox.c | 430 ---------------------------- arch/arm/plat-omap/Kconfig | 16 -- arch/arm/plat-omap/Makefile | 3 - arch/arm/plat-omap/include/plat/mailbox.h | 105 ------- arch/arm/plat-omap/mailbox.c | 435 ----------------------------- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/mailbox/Kconfig | 37 +++ drivers/mailbox/Makefile | 4 + drivers/mailbox/mailbox-omap1.c | 200 +++++++++++++ drivers/mailbox/mailbox-omap2.c | 430 ++++++++++++++++++++++++++++ drivers/mailbox/mailbox.c | 435 +++++++++++++++++++++++++++++ drivers/mailbox/mailbox.h | 105 +++++++ 18 files changed, 1218 insertions(+), 1198 deletions(-) delete mode 100644 arch/arm/mach-omap1/mailbox.c delete mode 100644 arch/arm/mach-omap2/mailbox.c delete mode 100644 arch/arm/plat-omap/include/plat/mailbox.h delete mode 100644 arch/arm/plat-omap/mailbox.c create mode 100644 drivers/mailbox/Kconfig create mode 100644 drivers/mailbox/Makefile create mode 100644 drivers/mailbox/mailbox-omap1.c create mode 100644 drivers/mailbox/mailbox-omap2.c create mode 100644 drivers/mailbox/mailbox.c create mode 100644 drivers/mailbox/mailbox.h diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index dde2a1a..37894db 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -26,7 +26,8 @@ CONFIG_ARCH_OMAP=y CONFIG_ARCH_OMAP1=y CONFIG_OMAP_RESET_CLOCKS=y # CONFIG_OMAP_MUX is not set -CONFIG_OMAP_MBOX_FWK=y +CONFIG_MAILBOX=y +CONFIG_OMAP1_MBOX=y CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_DM_TIMER=y CONFIG_ARCH_OMAP730=y diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index cd169c3..48275f8 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -18,10 +18,6 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o # Power Management obj-$(CONFIG_PM) += pm.o sleep.o -# DSP -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o -mailbox_mach-objs := mailbox.o - i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o obj-y += $(i2c-omap-m) $(i2c-omap-y) diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c deleted file mode 100644 index e962926..0000000 --- a/arch/arm/mach-omap1/mailbox.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Mailbox reservation modules for OMAP1 - * - * Copyright (C) 2006-2009 Nokia Corporation - * Written by: Hiroshi DOYU - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include - -#define MAILBOX_ARM2DSP1 0x00 -#define MAILBOX_ARM2DSP1b 0x04 -#define MAILBOX_DSP2ARM1 0x08 -#define MAILBOX_DSP2ARM1b 0x0c -#define MAILBOX_DSP2ARM2 0x10 -#define MAILBOX_DSP2ARM2b 0x14 -#define MAILBOX_ARM2DSP1_Flag 0x18 -#define MAILBOX_DSP2ARM1_Flag 0x1c -#define MAILBOX_DSP2ARM2_Flag 0x20 - -static void __iomem *mbox_base; - -struct omap_mbox1_fifo { - unsigned long cmd; - unsigned long data; - unsigned long flag; -}; - -struct omap_mbox1_priv { - struct omap_mbox1_fifo tx_fifo; - struct omap_mbox1_fifo rx_fifo; -}; - -static inline int mbox_read_reg(size_t ofs) -{ - return __raw_readw(mbox_base + ofs); -} - -static inline void mbox_write_reg(u32 val, size_t ofs) -{ - __raw_writew(val, mbox_base + ofs); -} - -/* msg */ -static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; - mbox_msg_t msg; - - msg = mbox_read_reg(fifo->data); - msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16; - - return msg; -} - -static void -omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo; - - mbox_write_reg(msg & 0xffff, fifo->data); - mbox_write_reg(msg >> 16, fifo->cmd); -} - -static int omap1_mbox_fifo_empty(struct omap_mbox *mbox) -{ - return 0; -} - -static int omap1_mbox_fifo_full(struct omap_mbox *mbox) -{ - struct omap_mbox1_fifo *fifo = - &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; - - return mbox_read_reg(fifo->flag); -} - -/* irq */ -static void -omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) -{ - if (irq == IRQ_RX) - enable_irq(mbox->irq); -} - -static void -omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) -{ - if (irq == IRQ_RX) - disable_irq(mbox->irq); -} - -static int -omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) -{ - if (irq == IRQ_TX) - return 0; - return 1; -} - -static struct omap_mbox_ops omap1_mbox_ops = { - .type = OMAP_MBOX_TYPE1, - .fifo_read = omap1_mbox_fifo_read, - .fifo_write = omap1_mbox_fifo_write, - .fifo_empty = omap1_mbox_fifo_empty, - .fifo_full = omap1_mbox_fifo_full, - .enable_irq = omap1_mbox_enable_irq, - .disable_irq = omap1_mbox_disable_irq, - .is_irq = omap1_mbox_is_irq, -}; - -/* FIXME: the following struct should be created automatically by the user id */ - -/* DSP */ -static struct omap_mbox1_priv omap1_mbox_dsp_priv = { - .tx_fifo = { - .cmd = MAILBOX_ARM2DSP1b, - .data = MAILBOX_ARM2DSP1, - .flag = MAILBOX_ARM2DSP1_Flag, - }, - .rx_fifo = { - .cmd = MAILBOX_DSP2ARM1b, - .data = MAILBOX_DSP2ARM1, - .flag = MAILBOX_DSP2ARM1_Flag, - }, -}; - -static struct omap_mbox mbox_dsp_info = { - .name = "dsp", - .ops = &omap1_mbox_ops, - .priv = &omap1_mbox_dsp_priv, -}; - -static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; - -static int __devinit omap1_mbox_probe(struct platform_device *pdev) -{ - struct resource *mem; - int ret; - struct omap_mbox **list; - - list = omap1_mboxes; - list[0]->irq = platform_get_irq_byname(pdev, "dsp"); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) - return -ENOMEM; - - ret = omap_mbox_register(&pdev->dev, list); - if (ret) { - iounmap(mbox_base); - return ret; - } - - return 0; -} - -static int __devexit omap1_mbox_remove(struct platform_device *pdev) -{ - omap_mbox_unregister(); - iounmap(mbox_base); - return 0; -} - -static struct platform_driver omap1_mbox_driver = { - .probe = omap1_mbox_probe, - .remove = __devexit_p(omap1_mbox_remove), - .driver = { - .name = "omap-mailbox", - }, -}; - -static int __init omap1_mbox_init(void) -{ - return platform_driver_register(&omap1_mbox_driver); -} - -static void __exit omap1_mbox_exit(void) -{ - platform_driver_unregister(&omap1_mbox_driver); -} - -module_init(omap1_mbox_init); -module_exit(omap1_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions"); -MODULE_AUTHOR("Hiroshi DOYU "); -MODULE_ALIAS("platform:omap1-mailbox"); diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index fe40d9e..3907fc5 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -181,9 +181,6 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o obj-$(CONFIG_OMAP3_EMU) += emu.o obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o -mailbox_mach-objs := mailbox.o - obj-$(CONFIG_OMAP_IOMMU) += iommu2.o iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index cba60e0..0dc1649 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -272,7 +272,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data return 0; } -#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE) +#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE) static inline void __init omap_init_mbox(void) { struct omap_hwmod *oh; @@ -290,7 +290,7 @@ static inline void __init omap_init_mbox(void) } #else static inline void omap_init_mbox(void) { } -#endif /* CONFIG_OMAP_MBOX_FWK */ +#endif /* CONFIG_OMAP2PLUS_MBOX */ static inline void omap_init_sti(void) {} diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c deleted file mode 100644 index 0d97456..0000000 --- a/arch/arm/mach-omap2/mailbox.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Mailbox reservation modules for OMAP2/3 - * - * Copyright (C) 2006-2009 Nokia Corporation - * Written by: Hiroshi DOYU - * and Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "soc.h" - -#define MAILBOX_REVISION 0x000 -#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) -#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) -#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) -#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) -#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) - -#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) - -#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) -#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) - -#define MBOX_REG_SIZE 0x120 - -#define OMAP4_MBOX_REG_SIZE 0x130 - -#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) -#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) - -static void __iomem *mbox_base; - -struct omap_mbox2_fifo { - unsigned long msg; - unsigned long fifo_stat; - unsigned long msg_stat; -}; - -struct omap_mbox2_priv { - struct omap_mbox2_fifo tx_fifo; - struct omap_mbox2_fifo rx_fifo; - unsigned long irqenable; - unsigned long irqstatus; - u32 newmsg_bit; - u32 notfull_bit; - u32 ctx[OMAP4_MBOX_NR_REGS]; - unsigned long irqdisable; -}; - -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq); - -static inline unsigned int mbox_read_reg(size_t ofs) -{ - return __raw_readl(mbox_base + ofs); -} - -static inline void mbox_write_reg(u32 val, size_t ofs) -{ - __raw_writel(val, mbox_base + ofs); -} - -/* Mailbox H/W preparations */ -static int omap2_mbox_startup(struct omap_mbox *mbox) -{ - u32 l; - - pm_runtime_enable(mbox->dev->parent); - pm_runtime_get_sync(mbox->dev->parent); - - l = mbox_read_reg(MAILBOX_REVISION); - pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); - - return 0; -} - -static void omap2_mbox_shutdown(struct omap_mbox *mbox) -{ - pm_runtime_put_sync(mbox->dev->parent); - pm_runtime_disable(mbox->dev->parent); -} - -/* Mailbox FIFO handle functions */ -static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; - return (mbox_msg_t) mbox_read_reg(fifo->msg); -} - -static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; - mbox_write_reg(msg, fifo->msg); -} - -static int omap2_mbox_fifo_empty(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; - return (mbox_read_reg(fifo->msg_stat) == 0); -} - -static int omap2_mbox_fifo_full(struct omap_mbox *mbox) -{ - struct omap_mbox2_fifo *fifo = - &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; - return mbox_read_reg(fifo->fifo_stat); -} - -/* Mailbox IRQ handle functions */ -static void omap2_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - l = mbox_read_reg(p->irqenable); - l |= bit; - mbox_write_reg(l, p->irqenable); -} - -static void omap2_mbox_disable_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - if (!cpu_is_omap44xx()) - bit = mbox_read_reg(p->irqdisable) & ~bit; - - mbox_write_reg(bit, p->irqdisable); -} - -static void omap2_mbox_ack_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - - mbox_write_reg(bit, p->irqstatus); - - /* Flush posted write for irq status to avoid spurious interrupts */ - mbox_read_reg(p->irqstatus); -} - -static int omap2_mbox_is_irq(struct omap_mbox *mbox, - omap_mbox_type_t irq) -{ - struct omap_mbox2_priv *p = mbox->priv; - u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; - u32 enable = mbox_read_reg(p->irqenable); - u32 status = mbox_read_reg(p->irqstatus); - - return (int)(enable & status & bit); -} - -static void omap2_mbox_save_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - if (cpu_is_omap44xx()) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - p->ctx[i] = mbox_read_reg(i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - -static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - if (cpu_is_omap44xx()) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - mbox_write_reg(p->ctx[i], i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - -static struct omap_mbox_ops omap2_mbox_ops = { - .type = OMAP_MBOX_TYPE2, - .startup = omap2_mbox_startup, - .shutdown = omap2_mbox_shutdown, - .fifo_read = omap2_mbox_fifo_read, - .fifo_write = omap2_mbox_fifo_write, - .fifo_empty = omap2_mbox_fifo_empty, - .fifo_full = omap2_mbox_fifo_full, - .enable_irq = omap2_mbox_enable_irq, - .disable_irq = omap2_mbox_disable_irq, - .ack_irq = omap2_mbox_ack_irq, - .is_irq = omap2_mbox_is_irq, - .save_ctx = omap2_mbox_save_ctx, - .restore_ctx = omap2_mbox_restore_ctx, -}; - -/* - * MAILBOX 0: ARM -> DSP, - * MAILBOX 1: ARM <- DSP. - * MAILBOX 2: ARM -> IVA, - * MAILBOX 3: ARM <- IVA. - */ - -/* FIXME: the following structs should be filled automatically by the user id */ - -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2) -/* DSP */ -static struct omap_mbox2_priv omap2_mbox_dsp_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(0), - .fifo_stat = MAILBOX_FIFOSTATUS(0), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(1), - .msg_stat = MAILBOX_MSGSTATUS(1), - }, - .irqenable = MAILBOX_IRQENABLE(0), - .irqstatus = MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(0), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), - .irqdisable = MAILBOX_IRQENABLE(0), -}; - -struct omap_mbox mbox_dsp_info = { - .name = "dsp", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_dsp_priv, -}; -#endif - -#if defined(CONFIG_ARCH_OMAP3) -struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; -#endif - -#if defined(CONFIG_SOC_OMAP2420) -/* IVA */ -static struct omap_mbox2_priv omap2_mbox_iva_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(2), - .fifo_stat = MAILBOX_FIFOSTATUS(2), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(3), - .msg_stat = MAILBOX_MSGSTATUS(3), - }, - .irqenable = MAILBOX_IRQENABLE(3), - .irqstatus = MAILBOX_IRQSTATUS(3), - .notfull_bit = MAILBOX_IRQ_NOTFULL(2), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(3), - .irqdisable = MAILBOX_IRQENABLE(3), -}; - -static struct omap_mbox mbox_iva_info = { - .name = "iva", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_iva_priv, -}; -#endif - -#ifdef CONFIG_ARCH_OMAP2 -struct omap_mbox *omap2_mboxes[] = { - &mbox_dsp_info, -#ifdef CONFIG_SOC_OMAP2420 - &mbox_iva_info, -#endif - NULL -}; -#endif - -#if defined(CONFIG_ARCH_OMAP4) -/* OMAP4 */ -static struct omap_mbox2_priv omap2_mbox_1_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(0), - .fifo_stat = MAILBOX_FIFOSTATUS(0), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(1), - .msg_stat = MAILBOX_MSGSTATUS(1), - }, - .irqenable = OMAP4_MAILBOX_IRQENABLE(0), - .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(0), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), - .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), -}; - -struct omap_mbox mbox_1_info = { - .name = "mailbox-1", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_1_priv, -}; - -static struct omap_mbox2_priv omap2_mbox_2_priv = { - .tx_fifo = { - .msg = MAILBOX_MESSAGE(3), - .fifo_stat = MAILBOX_FIFOSTATUS(3), - }, - .rx_fifo = { - .msg = MAILBOX_MESSAGE(2), - .msg_stat = MAILBOX_MSGSTATUS(2), - }, - .irqenable = OMAP4_MAILBOX_IRQENABLE(0), - .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), - .notfull_bit = MAILBOX_IRQ_NOTFULL(3), - .newmsg_bit = MAILBOX_IRQ_NEWMSG(2), - .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), -}; - -struct omap_mbox mbox_2_info = { - .name = "mailbox-2", - .ops = &omap2_mbox_ops, - .priv = &omap2_mbox_2_priv, -}; - -struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL }; -#endif - -static int __devinit omap2_mbox_probe(struct platform_device *pdev) -{ - struct resource *mem; - int ret; - struct omap_mbox **list; - - if (false) - ; -#if defined(CONFIG_ARCH_OMAP3) - else if (cpu_is_omap34xx()) { - list = omap3_mboxes; - - list[0]->irq = platform_get_irq(pdev, 0); - } -#endif -#if defined(CONFIG_ARCH_OMAP2) - else if (cpu_is_omap2430()) { - list = omap2_mboxes; - - list[0]->irq = platform_get_irq(pdev, 0); - } else if (cpu_is_omap2420()) { - list = omap2_mboxes; - - list[0]->irq = platform_get_irq_byname(pdev, "dsp"); - list[1]->irq = platform_get_irq_byname(pdev, "iva"); - } -#endif -#if defined(CONFIG_ARCH_OMAP4) - else if (cpu_is_omap44xx()) { - list = omap4_mboxes; - - list[0]->irq = list[1]->irq = platform_get_irq(pdev, 0); - } -#endif - else { - pr_err("%s: platform not supported\n", __func__); - return -ENODEV; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mbox_base = ioremap(mem->start, resource_size(mem)); - if (!mbox_base) - return -ENOMEM; - - ret = omap_mbox_register(&pdev->dev, list); - if (ret) { - iounmap(mbox_base); - return ret; - } - - return 0; -} - -static int __devexit omap2_mbox_remove(struct platform_device *pdev) -{ - omap_mbox_unregister(); - iounmap(mbox_base); - return 0; -} - -static struct platform_driver omap2_mbox_driver = { - .probe = omap2_mbox_probe, - .remove = __devexit_p(omap2_mbox_remove), - .driver = { - .name = "omap-mailbox", - }, -}; - -static int __init omap2_mbox_init(void) -{ - return platform_driver_register(&omap2_mbox_driver); -} - -static void __exit omap2_mbox_exit(void) -{ - platform_driver_unregister(&omap2_mbox_driver); -} - -module_init(omap2_mbox_init); -module_exit(omap2_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); -MODULE_AUTHOR("Hiroshi DOYU "); -MODULE_AUTHOR("Paul Mundt"); -MODULE_ALIAS("platform:omap2-mailbox"); diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 82fcb20..419648f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -116,22 +116,6 @@ config OMAP_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect OMAP_MUX for your product. -config OMAP_MBOX_FWK - tristate "Mailbox framework support" - depends on ARCH_OMAP - help - Say Y here if you want to use OMAP Mailbox framework support for - DSP, IVA1.0 and IVA2 in OMAP1/2/3. - -config OMAP_MBOX_KFIFO_SIZE - int "Mailbox kfifo default buffer size (bytes)" - depends on OMAP_MBOX_FWK - default 256 - help - Specify the default size of mailbox's kfifo buffers (bytes). - This can also be changed at runtime (via the mbox_kfifo_size - module parameter). - config OMAP_IOMMU_IVA2 bool diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index dacaee0..304fa78 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -17,7 +17,4 @@ obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o obj-y += $(i2c-omap-m) $(i2c-omap-y) -# OMAP mailbox framework -obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o - obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h deleted file mode 100644 index cc3921e..0000000 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ /dev/null @@ -1,105 +0,0 @@ -/* mailbox.h */ - -#ifndef MAILBOX_H -#define MAILBOX_H - -#include -#include -#include -#include -#include - -typedef u32 mbox_msg_t; -struct omap_mbox; - -typedef int __bitwise omap_mbox_irq_t; -#define IRQ_TX ((__force omap_mbox_irq_t) 1) -#define IRQ_RX ((__force omap_mbox_irq_t) 2) - -typedef int __bitwise omap_mbox_type_t; -#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1) -#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2) - -struct omap_mbox_ops { - omap_mbox_type_t type; - int (*startup)(struct omap_mbox *mbox); - void (*shutdown)(struct omap_mbox *mbox); - /* fifo */ - mbox_msg_t (*fifo_read)(struct omap_mbox *mbox); - void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg); - int (*fifo_empty)(struct omap_mbox *mbox); - int (*fifo_full)(struct omap_mbox *mbox); - /* irq */ - void (*enable_irq)(struct omap_mbox *mbox, - omap_mbox_irq_t irq); - void (*disable_irq)(struct omap_mbox *mbox, - omap_mbox_irq_t irq); - void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); - int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); - /* ctx */ - void (*save_ctx)(struct omap_mbox *mbox); - void (*restore_ctx)(struct omap_mbox *mbox); -}; - -struct omap_mbox_queue { - spinlock_t lock; - struct kfifo fifo; - struct work_struct work; - struct tasklet_struct tasklet; - struct omap_mbox *mbox; - bool full; -}; - -struct omap_mbox { - char *name; - unsigned int irq; - struct omap_mbox_queue *txq, *rxq; - struct omap_mbox_ops *ops; - struct device *dev; - void *priv; - int use_count; - struct blocking_notifier_head notifier; -}; - -int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); -void omap_mbox_init_seq(struct omap_mbox *); - -struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); - -int omap_mbox_register(struct device *parent, struct omap_mbox **); -int omap_mbox_unregister(void); - -static inline void omap_mbox_save_ctx(struct omap_mbox *mbox) -{ - if (!mbox->ops->save_ctx) { - dev_err(mbox->dev, "%s:\tno save\n", __func__); - return; - } - - mbox->ops->save_ctx(mbox); -} - -static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox) -{ - if (!mbox->ops->restore_ctx) { - dev_err(mbox->dev, "%s:\tno restore\n", __func__); - return; - } - - mbox->ops->restore_ctx(mbox); -} - -static inline void omap_mbox_enable_irq(struct omap_mbox *mbox, - omap_mbox_irq_t irq) -{ - mbox->ops->enable_irq(mbox, irq); -} - -static inline void omap_mbox_disable_irq(struct omap_mbox *mbox, - omap_mbox_irq_t irq) -{ - mbox->ops->disable_irq(mbox, irq); -} - -#endif /* MAILBOX_H */ diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c deleted file mode 100644 index 42377ef..0000000 --- a/arch/arm/plat-omap/mailbox.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * OMAP mailbox driver - * - * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. - * - * Contact: Hiroshi DOYU - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct omap_mbox **mboxes; - -static int mbox_configured; -static DEFINE_MUTEX(mbox_configured_lock); - -static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; -module_param(mbox_kfifo_size, uint, S_IRUGO); -MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); - -/* Mailbox FIFO handle functions */ -static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_read(mbox); -} -static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) -{ - mbox->ops->fifo_write(mbox, msg); -} -static inline int mbox_fifo_empty(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_empty(mbox); -} -static inline int mbox_fifo_full(struct omap_mbox *mbox) -{ - return mbox->ops->fifo_full(mbox); -} - -/* Mailbox IRQ handle functions */ -static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - if (mbox->ops->ack_irq) - mbox->ops->ack_irq(mbox, irq); -} -static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) -{ - return mbox->ops->is_irq(mbox, irq); -} - -/* - * message sender - */ -static int __mbox_poll_for_space(struct omap_mbox *mbox) -{ - int ret = 0, i = 1000; - - while (mbox_fifo_full(mbox)) { - if (mbox->ops->type == OMAP_MBOX_TYPE2) - return -1; - if (--i == 0) - return -1; - udelay(1); - } - return ret; -} - -int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) -{ - struct omap_mbox_queue *mq = mbox->txq; - int ret = 0, len; - - spin_lock_bh(&mq->lock); - - if (kfifo_avail(&mq->fifo) < sizeof(msg)) { - ret = -ENOMEM; - goto out; - } - - if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { - mbox_fifo_write(mbox, msg); - goto out; - } - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - tasklet_schedule(&mbox->txq->tasklet); - -out: - spin_unlock_bh(&mq->lock); - return ret; -} -EXPORT_SYMBOL(omap_mbox_msg_send); - -static void mbox_tx_tasklet(unsigned long tx_data) -{ - struct omap_mbox *mbox = (struct omap_mbox *)tx_data; - struct omap_mbox_queue *mq = mbox->txq; - mbox_msg_t msg; - int ret; - - while (kfifo_len(&mq->fifo)) { - if (__mbox_poll_for_space(mbox)) { - omap_mbox_enable_irq(mbox, IRQ_TX); - break; - } - - ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, - sizeof(msg)); - WARN_ON(ret != sizeof(msg)); - - mbox_fifo_write(mbox, msg); - } -} - -/* - * Message receiver(workqueue) - */ -static void mbox_rx_work(struct work_struct *work) -{ - struct omap_mbox_queue *mq = - container_of(work, struct omap_mbox_queue, work); - mbox_msg_t msg; - int len; - - while (kfifo_len(&mq->fifo) >= sizeof(msg)) { - len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - blocking_notifier_call_chain(&mq->mbox->notifier, len, - (void *)msg); - spin_lock_irq(&mq->lock); - if (mq->full) { - mq->full = false; - omap_mbox_enable_irq(mq->mbox, IRQ_RX); - } - spin_unlock_irq(&mq->lock); - } -} - -/* - * Mailbox interrupt handler - */ -static void __mbox_tx_interrupt(struct omap_mbox *mbox) -{ - omap_mbox_disable_irq(mbox, IRQ_TX); - ack_mbox_irq(mbox, IRQ_TX); - tasklet_schedule(&mbox->txq->tasklet); -} - -static void __mbox_rx_interrupt(struct omap_mbox *mbox) -{ - struct omap_mbox_queue *mq = mbox->rxq; - mbox_msg_t msg; - int len; - - while (!mbox_fifo_empty(mbox)) { - if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { - omap_mbox_disable_irq(mbox, IRQ_RX); - mq->full = true; - goto nomem; - } - - msg = mbox_fifo_read(mbox); - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - if (mbox->ops->type == OMAP_MBOX_TYPE1) - break; - } - - /* no more messages in the fifo. clear IRQ source. */ - ack_mbox_irq(mbox, IRQ_RX); -nomem: - schedule_work(&mbox->rxq->work); -} - -static irqreturn_t mbox_interrupt(int irq, void *p) -{ - struct omap_mbox *mbox = p; - - if (is_mbox_irq(mbox, IRQ_TX)) - __mbox_tx_interrupt(mbox); - - if (is_mbox_irq(mbox, IRQ_RX)) - __mbox_rx_interrupt(mbox); - - return IRQ_HANDLED; -} - -static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, - void (*work) (struct work_struct *), - void (*tasklet)(unsigned long)) -{ - struct omap_mbox_queue *mq; - - mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); - if (!mq) - return NULL; - - spin_lock_init(&mq->lock); - - if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) - goto error; - - if (work) - INIT_WORK(&mq->work, work); - - if (tasklet) - tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); - return mq; -error: - kfree(mq); - return NULL; -} - -static void mbox_queue_free(struct omap_mbox_queue *q) -{ - kfifo_free(&q->fifo); - kfree(q); -} - -static int omap_mbox_startup(struct omap_mbox *mbox) -{ - int ret = 0; - struct omap_mbox_queue *mq; - - mutex_lock(&mbox_configured_lock); - if (!mbox_configured++) { - if (likely(mbox->ops->startup)) { - ret = mbox->ops->startup(mbox); - if (unlikely(ret)) - goto fail_startup; - } else - goto fail_startup; - } - - if (!mbox->use_count++) { - ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, - mbox->name, mbox); - if (unlikely(ret)) { - pr_err("failed to register mailbox interrupt:%d\n", - ret); - goto fail_request_irq; - } - mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_txq; - } - mbox->txq = mq; - - mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_rxq; - } - mbox->rxq = mq; - mq->mbox = mbox; - - omap_mbox_enable_irq(mbox, IRQ_RX); - } - mutex_unlock(&mbox_configured_lock); - return 0; - -fail_alloc_rxq: - mbox_queue_free(mbox->txq); -fail_alloc_txq: - free_irq(mbox->irq, mbox); -fail_request_irq: - if (mbox->ops->shutdown) - mbox->ops->shutdown(mbox); - mbox->use_count--; -fail_startup: - mbox_configured--; - mutex_unlock(&mbox_configured_lock); - return ret; -} - -static void omap_mbox_fini(struct omap_mbox *mbox) -{ - mutex_lock(&mbox_configured_lock); - - if (!--mbox->use_count) { - omap_mbox_disable_irq(mbox, IRQ_RX); - free_irq(mbox->irq, mbox); - tasklet_kill(&mbox->txq->tasklet); - flush_work(&mbox->rxq->work); - mbox_queue_free(mbox->txq); - mbox_queue_free(mbox->rxq); - } - - if (likely(mbox->ops->shutdown)) { - if (!--mbox_configured) - mbox->ops->shutdown(mbox); - } - - mutex_unlock(&mbox_configured_lock); -} - -struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) -{ - struct omap_mbox *_mbox, *mbox = NULL; - int i, ret; - - if (!mboxes) - return ERR_PTR(-EINVAL); - - for (i = 0; (_mbox = mboxes[i]); i++) { - if (!strcmp(_mbox->name, name)) { - mbox = _mbox; - break; - } - } - - if (!mbox) - return ERR_PTR(-ENOENT); - - if (nb) - blocking_notifier_chain_register(&mbox->notifier, nb); - - ret = omap_mbox_startup(mbox); - if (ret) { - blocking_notifier_chain_unregister(&mbox->notifier, nb); - return ERR_PTR(-ENODEV); - } - - return mbox; -} -EXPORT_SYMBOL(omap_mbox_get); - -void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&mbox->notifier, nb); - omap_mbox_fini(mbox); -} -EXPORT_SYMBOL(omap_mbox_put); - -static struct class omap_mbox_class = { .name = "mbox", }; - -int omap_mbox_register(struct device *parent, struct omap_mbox **list) -{ - int ret; - int i; - - mboxes = list; - if (!mboxes) - return -EINVAL; - - for (i = 0; mboxes[i]; i++) { - struct omap_mbox *mbox = mboxes[i]; - mbox->dev = device_create(&omap_mbox_class, - parent, 0, mbox, "%s", mbox->name); - if (IS_ERR(mbox->dev)) { - ret = PTR_ERR(mbox->dev); - goto err_out; - } - - BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); - } - return 0; - -err_out: - while (i--) - device_unregister(mboxes[i]->dev); - return ret; -} -EXPORT_SYMBOL(omap_mbox_register); - -int omap_mbox_unregister(void) -{ - int i; - - if (!mboxes) - return -EINVAL; - - for (i = 0; mboxes[i]; i++) - device_unregister(mboxes[i]->dev); - mboxes = NULL; - return 0; -} -EXPORT_SYMBOL(omap_mbox_unregister); - -static int __init omap_mbox_init(void) -{ - int err; - - err = class_register(&omap_mbox_class); - if (err) - return err; - - /* kfifo size sanity check: alignment and minimal size */ - mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); - mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, - sizeof(mbox_msg_t)); - - return 0; -} -subsys_initcall(omap_mbox_init); - -static void __exit omap_mbox_exit(void) -{ - class_unregister(&omap_mbox_class); -} -module_exit(omap_mbox_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); -MODULE_AUTHOR("Toshihiro Kobayashi"); -MODULE_AUTHOR("Hiroshi DOYU"); diff --git a/drivers/Kconfig b/drivers/Kconfig index dbdefa3..7a4fb98 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -134,6 +134,8 @@ source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" +source "drivers/mailbox/Kconfig" + source "drivers/iommu/Kconfig" source "drivers/remoteproc/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index a16a8d0..78f2bf0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -132,6 +132,7 @@ obj-y += clk/ obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ obj-$(CONFIG_NFC) += nfc/ +obj-$(CONFIG_MAILBOX) += mailbox/ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/ obj-$(CONFIG_REMOTEPROC) += remoteproc/ obj-$(CONFIG_RPMSG) += rpmsg/ diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig new file mode 100644 index 0000000..be8cac0 --- /dev/null +++ b/drivers/mailbox/Kconfig @@ -0,0 +1,37 @@ +menuconfig MAILBOX + bool "Mailbox Hardware Support" + help + Mailbox is a framework to control hardware communication between + on-chip processors through queued messages and interrupt driven + signals. Say Y if your platform supports hardware mailboxes. + +if MAILBOX + +config OMAP1_MBOX + tristate "OMAP1 Mailbox framework support" + depends on ARCH_OMAP + help + Mailbox implementation for OMAP chips with hardware for + interprocessor communication involving DSP in OMAP1. Say Y here + if you want to use OMAP1 Mailbox framework support. + +config OMAP2PLUS_MBOX + tristate "OMAP2+ Mailbox framework support" + depends on ARCH_OMAP + help + Mailbox implementation for OMAP family chips with hardware for + interprocessor communication involving DSP, IVA1.0 and IVA2 in + OMAP2/3; or IPU, IVA HD and DSP in OMAP4. Say Y here if you want + to use OMAP2+ Mailbox framework support. + + +config OMAP_MBOX_KFIFO_SIZE + int "Mailbox kfifo default buffer size (bytes)" + depends on OMAP1_MBOX || OMAP2PLUS_MBOX + default 256 + help + Specify the default size of mailbox's kfifo buffers (bytes). + This can also be changed at runtime (via the mbox_kfifo_size + module parameter). + +endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile new file mode 100644 index 0000000..fa71fab --- /dev/null +++ b/drivers/mailbox/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_MAILBOX) += mailbox.o + +obj-$(CONFIG_OMAP1_MBOX) += mailbox-omap1.o +obj-$(CONFIG_OMAP2PLUS_MBOX) += mailbox-omap2.o diff --git a/drivers/mailbox/mailbox-omap1.c b/drivers/mailbox/mailbox-omap1.c new file mode 100644 index 0000000..8289a3b --- /dev/null +++ b/drivers/mailbox/mailbox-omap1.c @@ -0,0 +1,200 @@ +/* + * Mailbox reservation modules for OMAP1 + * + * Copyright (C) 2006-2009 Nokia Corporation + * Written by: Hiroshi DOYU + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include + +#include "mailbox.h" + +#define MAILBOX_ARM2DSP1 0x00 +#define MAILBOX_ARM2DSP1b 0x04 +#define MAILBOX_DSP2ARM1 0x08 +#define MAILBOX_DSP2ARM1b 0x0c +#define MAILBOX_DSP2ARM2 0x10 +#define MAILBOX_DSP2ARM2b 0x14 +#define MAILBOX_ARM2DSP1_Flag 0x18 +#define MAILBOX_DSP2ARM1_Flag 0x1c +#define MAILBOX_DSP2ARM2_Flag 0x20 + +static void __iomem *mbox_base; + +struct omap_mbox1_fifo { + unsigned long cmd; + unsigned long data; + unsigned long flag; +}; + +struct omap_mbox1_priv { + struct omap_mbox1_fifo tx_fifo; + struct omap_mbox1_fifo rx_fifo; +}; + +static inline int mbox_read_reg(size_t ofs) +{ + return __raw_readw(mbox_base + ofs); +} + +static inline void mbox_write_reg(u32 val, size_t ofs) +{ + __raw_writew(val, mbox_base + ofs); +} + +/* msg */ +static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; + mbox_msg_t msg; + + msg = mbox_read_reg(fifo->data); + msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16; + + return msg; +} + +static void +omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo; + + mbox_write_reg(msg & 0xffff, fifo->data); + mbox_write_reg(msg >> 16, fifo->cmd); +} + +static int omap1_mbox_fifo_empty(struct omap_mbox *mbox) +{ + return 0; +} + +static int omap1_mbox_fifo_full(struct omap_mbox *mbox) +{ + struct omap_mbox1_fifo *fifo = + &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; + + return mbox_read_reg(fifo->flag); +} + +/* irq */ +static void +omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +{ + if (irq == IRQ_RX) + enable_irq(mbox->irq); +} + +static void +omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +{ + if (irq == IRQ_RX) + disable_irq(mbox->irq); +} + +static int +omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq) +{ + if (irq == IRQ_TX) + return 0; + return 1; +} + +static struct omap_mbox_ops omap1_mbox_ops = { + .type = OMAP_MBOX_TYPE1, + .fifo_read = omap1_mbox_fifo_read, + .fifo_write = omap1_mbox_fifo_write, + .fifo_empty = omap1_mbox_fifo_empty, + .fifo_full = omap1_mbox_fifo_full, + .enable_irq = omap1_mbox_enable_irq, + .disable_irq = omap1_mbox_disable_irq, + .is_irq = omap1_mbox_is_irq, +}; + +/* FIXME: the following struct should be created automatically by the user id */ + +/* DSP */ +static struct omap_mbox1_priv omap1_mbox_dsp_priv = { + .tx_fifo = { + .cmd = MAILBOX_ARM2DSP1b, + .data = MAILBOX_ARM2DSP1, + .flag = MAILBOX_ARM2DSP1_Flag, + }, + .rx_fifo = { + .cmd = MAILBOX_DSP2ARM1b, + .data = MAILBOX_DSP2ARM1, + .flag = MAILBOX_DSP2ARM1_Flag, + }, +}; + +static struct omap_mbox mbox_dsp_info = { + .name = "dsp", + .ops = &omap1_mbox_ops, + .priv = &omap1_mbox_dsp_priv, +}; + +static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; + +static int __devinit omap1_mbox_probe(struct platform_device *pdev) +{ + struct resource *mem; + int ret; + struct omap_mbox **list; + + list = omap1_mboxes; + list[0]->irq = platform_get_irq_byname(pdev, "dsp"); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mbox_base = ioremap(mem->start, resource_size(mem)); + if (!mbox_base) + return -ENOMEM; + + ret = omap_mbox_register(&pdev->dev, list); + if (ret) { + iounmap(mbox_base); + return ret; + } + + return 0; +} + +static int __devexit omap1_mbox_remove(struct platform_device *pdev) +{ + omap_mbox_unregister(); + iounmap(mbox_base); + return 0; +} + +static struct platform_driver omap1_mbox_driver = { + .probe = omap1_mbox_probe, + .remove = __devexit_p(omap1_mbox_remove), + .driver = { + .name = "omap-mailbox", + }, +}; + +static int __init omap1_mbox_init(void) +{ + return platform_driver_register(&omap1_mbox_driver); +} + +static void __exit omap1_mbox_exit(void) +{ + platform_driver_unregister(&omap1_mbox_driver); +} + +module_init(omap1_mbox_init); +module_exit(omap1_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions"); +MODULE_AUTHOR("Hiroshi DOYU "); +MODULE_ALIAS("platform:omap1-mailbox"); diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c new file mode 100644 index 0000000..3c6c02a --- /dev/null +++ b/drivers/mailbox/mailbox-omap2.c @@ -0,0 +1,430 @@ +/* + * Mailbox reservation modules for OMAP2/3 + * + * Copyright (C) 2006-2009 Nokia Corporation + * Written by: Hiroshi DOYU + * and Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "mailbox.h" + +#define MAILBOX_REVISION 0x000 +#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) +#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) +#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) +#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) +#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) + +#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) + +#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) +#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) + +#define MBOX_REG_SIZE 0x120 + +#define OMAP4_MBOX_REG_SIZE 0x130 + +#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) +#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) + +static void __iomem *mbox_base; + +struct omap_mbox2_fifo { + unsigned long msg; + unsigned long fifo_stat; + unsigned long msg_stat; +}; + +struct omap_mbox2_priv { + struct omap_mbox2_fifo tx_fifo; + struct omap_mbox2_fifo rx_fifo; + unsigned long irqenable; + unsigned long irqstatus; + u32 newmsg_bit; + u32 notfull_bit; + u32 ctx[OMAP4_MBOX_NR_REGS]; + unsigned long irqdisable; +}; + +static void omap2_mbox_enable_irq(struct omap_mbox *mbox, + omap_mbox_type_t irq); + +static inline unsigned int mbox_read_reg(size_t ofs) +{ + return __raw_readl(mbox_base + ofs); +} + +static inline void mbox_write_reg(u32 val, size_t ofs) +{ + __raw_writel(val, mbox_base + ofs); +} + +/* Mailbox H/W preparations */ +static int omap2_mbox_startup(struct omap_mbox *mbox) +{ + u32 l; + + pm_runtime_enable(mbox->dev->parent); + pm_runtime_get_sync(mbox->dev->parent); + + l = mbox_read_reg(MAILBOX_REVISION); + pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); + + return 0; +} + +static void omap2_mbox_shutdown(struct omap_mbox *mbox) +{ + pm_runtime_put_sync(mbox->dev->parent); + pm_runtime_disable(mbox->dev->parent); +} + +/* Mailbox FIFO handle functions */ +static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; + return (mbox_msg_t) mbox_read_reg(fifo->msg); +} + +static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; + mbox_write_reg(msg, fifo->msg); +} + +static int omap2_mbox_fifo_empty(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; + return (mbox_read_reg(fifo->msg_stat) == 0); +} + +static int omap2_mbox_fifo_full(struct omap_mbox *mbox) +{ + struct omap_mbox2_fifo *fifo = + &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; + return mbox_read_reg(fifo->fifo_stat); +} + +/* Mailbox IRQ handle functions */ +static void omap2_mbox_enable_irq(struct omap_mbox *mbox, + omap_mbox_type_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + l = mbox_read_reg(p->irqenable); + l |= bit; + mbox_write_reg(l, p->irqenable); +} + +static void omap2_mbox_disable_irq(struct omap_mbox *mbox, + omap_mbox_type_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + if (!cpu_is_omap44xx()) + bit = mbox_read_reg(p->irqdisable) & ~bit; + + mbox_write_reg(bit, p->irqdisable); +} + +static void omap2_mbox_ack_irq(struct omap_mbox *mbox, + omap_mbox_type_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + + mbox_write_reg(bit, p->irqstatus); + + /* Flush posted write for irq status to avoid spurious interrupts */ + mbox_read_reg(p->irqstatus); +} + +static int omap2_mbox_is_irq(struct omap_mbox *mbox, + omap_mbox_type_t irq) +{ + struct omap_mbox2_priv *p = mbox->priv; + u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; + u32 enable = mbox_read_reg(p->irqenable); + u32 status = mbox_read_reg(p->irqstatus); + + return (int)(enable & status & bit); +} + +static void omap2_mbox_save_ctx(struct omap_mbox *mbox) +{ + int i; + struct omap_mbox2_priv *p = mbox->priv; + int nr_regs; + if (cpu_is_omap44xx()) + nr_regs = OMAP4_MBOX_NR_REGS; + else + nr_regs = MBOX_NR_REGS; + for (i = 0; i < nr_regs; i++) { + p->ctx[i] = mbox_read_reg(i * sizeof(u32)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, p->ctx[i]); + } +} + +static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) +{ + int i; + struct omap_mbox2_priv *p = mbox->priv; + int nr_regs; + if (cpu_is_omap44xx()) + nr_regs = OMAP4_MBOX_NR_REGS; + else + nr_regs = MBOX_NR_REGS; + for (i = 0; i < nr_regs; i++) { + mbox_write_reg(p->ctx[i], i * sizeof(u32)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, p->ctx[i]); + } +} + +static struct omap_mbox_ops omap2_mbox_ops = { + .type = OMAP_MBOX_TYPE2, + .startup = omap2_mbox_startup, + .shutdown = omap2_mbox_shutdown, + .fifo_read = omap2_mbox_fifo_read, + .fifo_write = omap2_mbox_fifo_write, + .fifo_empty = omap2_mbox_fifo_empty, + .fifo_full = omap2_mbox_fifo_full, + .enable_irq = omap2_mbox_enable_irq, + .disable_irq = omap2_mbox_disable_irq, + .ack_irq = omap2_mbox_ack_irq, + .is_irq = omap2_mbox_is_irq, + .save_ctx = omap2_mbox_save_ctx, + .restore_ctx = omap2_mbox_restore_ctx, +}; + +/* + * MAILBOX 0: ARM -> DSP, + * MAILBOX 1: ARM <- DSP. + * MAILBOX 2: ARM -> IVA, + * MAILBOX 3: ARM <- IVA. + */ + +/* FIXME: the following structs should be filled automatically by the user id */ + +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2) +/* DSP */ +static struct omap_mbox2_priv omap2_mbox_dsp_priv = { + .tx_fifo = { + .msg = MAILBOX_MESSAGE(0), + .fifo_stat = MAILBOX_FIFOSTATUS(0), + }, + .rx_fifo = { + .msg = MAILBOX_MESSAGE(1), + .msg_stat = MAILBOX_MSGSTATUS(1), + }, + .irqenable = MAILBOX_IRQENABLE(0), + .irqstatus = MAILBOX_IRQSTATUS(0), + .notfull_bit = MAILBOX_IRQ_NOTFULL(0), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), + .irqdisable = MAILBOX_IRQENABLE(0), +}; + +struct omap_mbox mbox_dsp_info = { + .name = "dsp", + .ops = &omap2_mbox_ops, + .priv = &omap2_mbox_dsp_priv, +}; +#endif + +#if defined(CONFIG_ARCH_OMAP3) +struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; +#endif + +#if defined(CONFIG_SOC_OMAP2420) +/* IVA */ +static struct omap_mbox2_priv omap2_mbox_iva_priv = { + .tx_fifo = { + .msg = MAILBOX_MESSAGE(2), + .fifo_stat = MAILBOX_FIFOSTATUS(2), + }, + .rx_fifo = { + .msg = MAILBOX_MESSAGE(3), + .msg_stat = MAILBOX_MSGSTATUS(3), + }, + .irqenable = MAILBOX_IRQENABLE(3), + .irqstatus = MAILBOX_IRQSTATUS(3), + .notfull_bit = MAILBOX_IRQ_NOTFULL(2), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(3), + .irqdisable = MAILBOX_IRQENABLE(3), +}; + +static struct omap_mbox mbox_iva_info = { + .name = "iva", + .ops = &omap2_mbox_ops, + .priv = &omap2_mbox_iva_priv, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP2 +struct omap_mbox *omap2_mboxes[] = { + &mbox_dsp_info, +#ifdef CONFIG_SOC_OMAP2420 + &mbox_iva_info, +#endif + NULL +}; +#endif + +#if defined(CONFIG_ARCH_OMAP4) +/* OMAP4 */ +static struct omap_mbox2_priv omap2_mbox_1_priv = { + .tx_fifo = { + .msg = MAILBOX_MESSAGE(0), + .fifo_stat = MAILBOX_FIFOSTATUS(0), + }, + .rx_fifo = { + .msg = MAILBOX_MESSAGE(1), + .msg_stat = MAILBOX_MSGSTATUS(1), + }, + .irqenable = OMAP4_MAILBOX_IRQENABLE(0), + .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), + .notfull_bit = MAILBOX_IRQ_NOTFULL(0), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(1), + .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), +}; + +struct omap_mbox mbox_1_info = { + .name = "mailbox-1", + .ops = &omap2_mbox_ops, + .priv = &omap2_mbox_1_priv, +}; + +static struct omap_mbox2_priv omap2_mbox_2_priv = { + .tx_fifo = { + .msg = MAILBOX_MESSAGE(3), + .fifo_stat = MAILBOX_FIFOSTATUS(3), + }, + .rx_fifo = { + .msg = MAILBOX_MESSAGE(2), + .msg_stat = MAILBOX_MSGSTATUS(2), + }, + .irqenable = OMAP4_MAILBOX_IRQENABLE(0), + .irqstatus = OMAP4_MAILBOX_IRQSTATUS(0), + .notfull_bit = MAILBOX_IRQ_NOTFULL(3), + .newmsg_bit = MAILBOX_IRQ_NEWMSG(2), + .irqdisable = OMAP4_MAILBOX_IRQENABLE_CLR(0), +}; + +struct omap_mbox mbox_2_info = { + .name = "mailbox-2", + .ops = &omap2_mbox_ops, + .priv = &omap2_mbox_2_priv, +}; + +struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL }; +#endif + +static int __devinit omap2_mbox_probe(struct platform_device *pdev) +{ + struct resource *mem; + int ret; + struct omap_mbox **list; + + if (false) + ; +#if defined(CONFIG_ARCH_OMAP3) + else if (cpu_is_omap34xx()) { + list = omap3_mboxes; + + list[0]->irq = platform_get_irq(pdev, 0); + } +#endif +#if defined(CONFIG_ARCH_OMAP2) + else if (cpu_is_omap2430()) { + list = omap2_mboxes; + + list[0]->irq = platform_get_irq(pdev, 0); + } else if (cpu_is_omap2420()) { + list = omap2_mboxes; + + list[0]->irq = platform_get_irq_byname(pdev, "dsp"); + list[1]->irq = platform_get_irq_byname(pdev, "iva"); + } +#endif +#if defined(CONFIG_ARCH_OMAP4) + else if (cpu_is_omap44xx()) { + list = omap4_mboxes; + + list[0]->irq = list[1]->irq = platform_get_irq(pdev, 0); + } +#endif + else { + pr_err("%s: platform not supported\n", __func__); + return -ENODEV; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mbox_base = ioremap(mem->start, resource_size(mem)); + if (!mbox_base) + return -ENOMEM; + + ret = omap_mbox_register(&pdev->dev, list); + if (ret) { + iounmap(mbox_base); + return ret; + } + + return 0; +} + +static int __devexit omap2_mbox_remove(struct platform_device *pdev) +{ + omap_mbox_unregister(); + iounmap(mbox_base); + return 0; +} + +static struct platform_driver omap2_mbox_driver = { + .probe = omap2_mbox_probe, + .remove = __devexit_p(omap2_mbox_remove), + .driver = { + .name = "omap-mailbox", + }, +}; + +static int __init omap2_mbox_init(void) +{ + return platform_driver_register(&omap2_mbox_driver); +} + +static void __exit omap2_mbox_exit(void) +{ + platform_driver_unregister(&omap2_mbox_driver); +} + +module_init(omap2_mbox_init); +module_exit(omap2_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); +MODULE_AUTHOR("Hiroshi DOYU "); +MODULE_AUTHOR("Paul Mundt"); +MODULE_ALIAS("platform:omap2-mailbox"); diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c new file mode 100644 index 0000000..6346ad3 --- /dev/null +++ b/drivers/mailbox/mailbox.c @@ -0,0 +1,435 @@ +/* + * OMAP mailbox driver + * + * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. + * + * Contact: Hiroshi DOYU + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mailbox.h" + +static struct omap_mbox **mboxes; + +static int mbox_configured; +static DEFINE_MUTEX(mbox_configured_lock); + +static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; +module_param(mbox_kfifo_size, uint, S_IRUGO); +MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); + +/* Mailbox FIFO handle functions */ +static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_read(mbox); +} +static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox->ops->fifo_write(mbox, msg); +} +static inline int mbox_fifo_empty(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_empty(mbox); +} +static inline int mbox_fifo_full(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_full(mbox); +} + +/* Mailbox IRQ handle functions */ +static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (mbox->ops->ack_irq) + mbox->ops->ack_irq(mbox, irq); +} +static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + return mbox->ops->is_irq(mbox, irq); +} + +/* + * message sender + */ +static int __mbox_poll_for_space(struct omap_mbox *mbox) +{ + int ret = 0, i = 1000; + + while (mbox_fifo_full(mbox)) { + if (mbox->ops->type == OMAP_MBOX_TYPE2) + return -1; + if (--i == 0) + return -1; + udelay(1); + } + return ret; +} + +int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) +{ + struct omap_mbox_queue *mq = mbox->txq; + int ret = 0, len; + + spin_lock_bh(&mq->lock); + + if (kfifo_avail(&mq->fifo) < sizeof(msg)) { + ret = -ENOMEM; + goto out; + } + + if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { + mbox_fifo_write(mbox, msg); + goto out; + } + + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + tasklet_schedule(&mbox->txq->tasklet); + +out: + spin_unlock_bh(&mq->lock); + return ret; +} +EXPORT_SYMBOL(omap_mbox_msg_send); + +static void mbox_tx_tasklet(unsigned long tx_data) +{ + struct omap_mbox *mbox = (struct omap_mbox *)tx_data; + struct omap_mbox_queue *mq = mbox->txq; + mbox_msg_t msg; + int ret; + + while (kfifo_len(&mq->fifo)) { + if (__mbox_poll_for_space(mbox)) { + omap_mbox_enable_irq(mbox, IRQ_TX); + break; + } + + ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, + sizeof(msg)); + WARN_ON(ret != sizeof(msg)); + + mbox_fifo_write(mbox, msg); + } +} + +/* + * Message receiver(workqueue) + */ +static void mbox_rx_work(struct work_struct *work) +{ + struct omap_mbox_queue *mq = + container_of(work, struct omap_mbox_queue, work); + mbox_msg_t msg; + int len; + + while (kfifo_len(&mq->fifo) >= sizeof(msg)) { + len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + blocking_notifier_call_chain(&mq->mbox->notifier, len, + (void *)msg); + spin_lock_irq(&mq->lock); + if (mq->full) { + mq->full = false; + omap_mbox_enable_irq(mq->mbox, IRQ_RX); + } + spin_unlock_irq(&mq->lock); + } +} + +/* + * Mailbox interrupt handler + */ +static void __mbox_tx_interrupt(struct omap_mbox *mbox) +{ + omap_mbox_disable_irq(mbox, IRQ_TX); + ack_mbox_irq(mbox, IRQ_TX); + tasklet_schedule(&mbox->txq->tasklet); +} + +static void __mbox_rx_interrupt(struct omap_mbox *mbox) +{ + struct omap_mbox_queue *mq = mbox->rxq; + mbox_msg_t msg; + int len; + + while (!mbox_fifo_empty(mbox)) { + if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { + omap_mbox_disable_irq(mbox, IRQ_RX); + mq->full = true; + goto nomem; + } + + msg = mbox_fifo_read(mbox); + + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); + WARN_ON(len != sizeof(msg)); + + if (mbox->ops->type == OMAP_MBOX_TYPE1) + break; + } + + /* no more messages in the fifo. clear IRQ source. */ + ack_mbox_irq(mbox, IRQ_RX); +nomem: + schedule_work(&mbox->rxq->work); +} + +static irqreturn_t mbox_interrupt(int irq, void *p) +{ + struct omap_mbox *mbox = p; + + if (is_mbox_irq(mbox, IRQ_TX)) + __mbox_tx_interrupt(mbox); + + if (is_mbox_irq(mbox, IRQ_RX)) + __mbox_rx_interrupt(mbox); + + return IRQ_HANDLED; +} + +static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, + void (*work) (struct work_struct *), + void (*tasklet)(unsigned long)) +{ + struct omap_mbox_queue *mq; + + mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); + if (!mq) + return NULL; + + spin_lock_init(&mq->lock); + + if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) + goto error; + + if (work) + INIT_WORK(&mq->work, work); + + if (tasklet) + tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); + return mq; +error: + kfree(mq); + return NULL; +} + +static void mbox_queue_free(struct omap_mbox_queue *q) +{ + kfifo_free(&q->fifo); + kfree(q); +} + +static int omap_mbox_startup(struct omap_mbox *mbox) +{ + int ret = 0; + struct omap_mbox_queue *mq; + + mutex_lock(&mbox_configured_lock); + if (!mbox_configured++) { + if (likely(mbox->ops->startup)) { + ret = mbox->ops->startup(mbox); + if (unlikely(ret)) + goto fail_startup; + } else + goto fail_startup; + } + + if (!mbox->use_count++) { + ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, + mbox->name, mbox); + if (unlikely(ret)) { + pr_err("failed to register mailbox interrupt:%d\n", + ret); + goto fail_request_irq; + } + mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_txq; + } + mbox->txq = mq; + + mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_rxq; + } + mbox->rxq = mq; + mq->mbox = mbox; + + omap_mbox_enable_irq(mbox, IRQ_RX); + } + mutex_unlock(&mbox_configured_lock); + return 0; + +fail_alloc_rxq: + mbox_queue_free(mbox->txq); +fail_alloc_txq: + free_irq(mbox->irq, mbox); +fail_request_irq: + if (mbox->ops->shutdown) + mbox->ops->shutdown(mbox); + mbox->use_count--; +fail_startup: + mbox_configured--; + mutex_unlock(&mbox_configured_lock); + return ret; +} + +static void omap_mbox_fini(struct omap_mbox *mbox) +{ + mutex_lock(&mbox_configured_lock); + + if (!--mbox->use_count) { + omap_mbox_disable_irq(mbox, IRQ_RX); + free_irq(mbox->irq, mbox); + tasklet_kill(&mbox->txq->tasklet); + flush_work(&mbox->rxq->work); + mbox_queue_free(mbox->txq); + mbox_queue_free(mbox->rxq); + } + + if (likely(mbox->ops->shutdown)) { + if (!--mbox_configured) + mbox->ops->shutdown(mbox); + } + + mutex_unlock(&mbox_configured_lock); +} + +struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) +{ + struct omap_mbox *_mbox, *mbox = NULL; + int i, ret; + + if (!mboxes) + return ERR_PTR(-EINVAL); + + for (i = 0; (_mbox = mboxes[i]); i++) { + if (!strcmp(_mbox->name, name)) { + mbox = _mbox; + break; + } + } + + if (!mbox) + return ERR_PTR(-ENOENT); + + if (nb) + blocking_notifier_chain_register(&mbox->notifier, nb); + + ret = omap_mbox_startup(mbox); + if (ret) { + blocking_notifier_chain_unregister(&mbox->notifier, nb); + return ERR_PTR(-ENODEV); + } + + return mbox; +} +EXPORT_SYMBOL(omap_mbox_get); + +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&mbox->notifier, nb); + omap_mbox_fini(mbox); +} +EXPORT_SYMBOL(omap_mbox_put); + +static struct class omap_mbox_class = { .name = "mbox", }; + +int omap_mbox_register(struct device *parent, struct omap_mbox **list) +{ + int ret; + int i; + + mboxes = list; + if (!mboxes) + return -EINVAL; + + for (i = 0; mboxes[i]; i++) { + struct omap_mbox *mbox = mboxes[i]; + mbox->dev = device_create(&omap_mbox_class, + parent, 0, mbox, "%s", mbox->name); + if (IS_ERR(mbox->dev)) { + ret = PTR_ERR(mbox->dev); + goto err_out; + } + + BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); + } + return 0; + +err_out: + while (i--) + device_unregister(mboxes[i]->dev); + return ret; +} +EXPORT_SYMBOL(omap_mbox_register); + +int omap_mbox_unregister(void) +{ + int i; + + if (!mboxes) + return -EINVAL; + + for (i = 0; mboxes[i]; i++) + device_unregister(mboxes[i]->dev); + mboxes = NULL; + return 0; +} +EXPORT_SYMBOL(omap_mbox_unregister); + +static int __init omap_mbox_init(void) +{ + int err; + + err = class_register(&omap_mbox_class); + if (err) + return err; + + /* kfifo size sanity check: alignment and minimal size */ + mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); + mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, + sizeof(mbox_msg_t)); + + return 0; +} +subsys_initcall(omap_mbox_init); + +static void __exit omap_mbox_exit(void) +{ + class_unregister(&omap_mbox_class); +} +module_exit(omap_mbox_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); +MODULE_AUTHOR("Toshihiro Kobayashi"); +MODULE_AUTHOR("Hiroshi DOYU"); diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h new file mode 100644 index 0000000..cc3921e --- /dev/null +++ b/drivers/mailbox/mailbox.h @@ -0,0 +1,105 @@ +/* mailbox.h */ + +#ifndef MAILBOX_H +#define MAILBOX_H + +#include +#include +#include +#include +#include + +typedef u32 mbox_msg_t; +struct omap_mbox; + +typedef int __bitwise omap_mbox_irq_t; +#define IRQ_TX ((__force omap_mbox_irq_t) 1) +#define IRQ_RX ((__force omap_mbox_irq_t) 2) + +typedef int __bitwise omap_mbox_type_t; +#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1) +#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2) + +struct omap_mbox_ops { + omap_mbox_type_t type; + int (*startup)(struct omap_mbox *mbox); + void (*shutdown)(struct omap_mbox *mbox); + /* fifo */ + mbox_msg_t (*fifo_read)(struct omap_mbox *mbox); + void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg); + int (*fifo_empty)(struct omap_mbox *mbox); + int (*fifo_full)(struct omap_mbox *mbox); + /* irq */ + void (*enable_irq)(struct omap_mbox *mbox, + omap_mbox_irq_t irq); + void (*disable_irq)(struct omap_mbox *mbox, + omap_mbox_irq_t irq); + void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); + int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); + /* ctx */ + void (*save_ctx)(struct omap_mbox *mbox); + void (*restore_ctx)(struct omap_mbox *mbox); +}; + +struct omap_mbox_queue { + spinlock_t lock; + struct kfifo fifo; + struct work_struct work; + struct tasklet_struct tasklet; + struct omap_mbox *mbox; + bool full; +}; + +struct omap_mbox { + char *name; + unsigned int irq; + struct omap_mbox_queue *txq, *rxq; + struct omap_mbox_ops *ops; + struct device *dev; + void *priv; + int use_count; + struct blocking_notifier_head notifier; +}; + +int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); +void omap_mbox_init_seq(struct omap_mbox *); + +struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); + +int omap_mbox_register(struct device *parent, struct omap_mbox **); +int omap_mbox_unregister(void); + +static inline void omap_mbox_save_ctx(struct omap_mbox *mbox) +{ + if (!mbox->ops->save_ctx) { + dev_err(mbox->dev, "%s:\tno save\n", __func__); + return; + } + + mbox->ops->save_ctx(mbox); +} + +static inline void omap_mbox_restore_ctx(struct omap_mbox *mbox) +{ + if (!mbox->ops->restore_ctx) { + dev_err(mbox->dev, "%s:\tno restore\n", __func__); + return; + } + + mbox->ops->restore_ctx(mbox); +} + +static inline void omap_mbox_enable_irq(struct omap_mbox *mbox, + omap_mbox_irq_t irq) +{ + mbox->ops->enable_irq(mbox, irq); +} + +static inline void omap_mbox_disable_irq(struct omap_mbox *mbox, + omap_mbox_irq_t irq) +{ + mbox->ops->disable_irq(mbox, irq); +} + +#endif /* MAILBOX_H */