summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorDima Zavin <dima@android.com>2010-12-14 14:12:05 -0800
committerDima Zavin <dima@android.com>2010-12-14 14:12:05 -0800
commit2da4db5bffe757188b0a06235e5e68505a5c20c4 (patch)
tree23bda60cab591c6f065ec58d11d84a2e0335371b /arch/arm
parent98bf149e45c7a6e93d2c09ff789f1e7c970ec9a7 (diff)
parent8fc88f1863d8130419ce3f10ff4e50e013425101 (diff)
Merge remote branch 'tegra/linux-tegra-2.6.36' into android-tegra-2.6.36
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/Kconfig3
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/arb_sema.c242
-rw-r--r--arch/arm/mach-tegra/board-ventana.c1
-rw-r--r--arch/arm/mach-tegra/devices.c21
-rw-r--r--arch/arm/mach-tegra/devices.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/arb_sema.h34
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h9
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c1
9 files changed, 313 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 8269eea7ee77..edaff55f1f01 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -100,3 +100,6 @@ config TEGRA_IOVMM_GART
config TEGRA_IOVMM
bool
+
+config TEGRA_ARB_SEMAPHORE
+ bool
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 9b8bdf9f5625..b2374b94d9ea 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
obj-$(CONFIG_FIQ) += fiq.o
obj-$(CONFIG_TEGRA_FIQ_DEBUGGER) += tegra_fiq_debugger.o
obj-$(CONFIG_TEGRA_PWM) += pwm.o
+obj-$(CONFIG_TEGRA_ARB_SEMAPHORE) += arb_sema.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
diff --git a/arch/arm/mach-tegra/arb_sema.c b/arch/arm/mach-tegra/arb_sema.c
new file mode 100644
index 000000000000..55af15e935f2
--- /dev/null
+++ b/arch/arm/mach-tegra/arb_sema.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2010, NVIDIA Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+
+#include <mach/arb_sema.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+
+#define TEGRA_RPC_MAX_SEM 32
+
+/* arb_gnt ictrl */
+#define ARB_CPU_INT_EN 0x4
+
+/* arb_sema */
+#define ARB_GRANT_STATUS 0x0
+#define ARB_GRANT_REQUEST 0x4
+#define ARB_GRANT_RELEASE 0x8
+
+struct tegra_arb_dev {
+ void __iomem *sema_base;
+ void __iomem *gnt_base;
+ spinlock_t lock;
+ struct completion arb_gnt_complete[TEGRA_RPC_MAX_SEM];
+ struct mutex mutexes[TEGRA_RPC_MAX_SEM];
+ int irq;
+ int status;
+ bool suspended;
+};
+
+static struct tegra_arb_dev *arb;
+
+static inline u32 arb_sema_read(u32 offset)
+{
+ return readl(arb->sema_base + offset);
+}
+
+static inline void arb_sema_write(u32 value, u32 offset)
+{
+ writel(value, arb->sema_base + offset);
+}
+
+static inline u32 arb_gnt_read(u32 offset)
+{
+ return readl(arb->gnt_base + offset);
+}
+
+static inline void arb_gnt_write(u32 value, u32 offset)
+{
+ writel(value, arb->gnt_base + offset);
+}
+
+static void request_arb_sem(enum tegra_arb_module lock)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&arb->lock, flags);
+
+ arb_sema_write(1 << lock, ARB_GRANT_REQUEST);
+ value = arb_gnt_read(ARB_CPU_INT_EN);
+ value |= (1 << lock);
+ arb_gnt_write(value, ARB_CPU_INT_EN);
+
+ spin_unlock_irqrestore(&arb->lock, flags);
+}
+
+static void cancel_arb_sem(enum tegra_arb_module lock)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&arb->lock, flags);
+
+ arb_sema_write(1 << lock, ARB_GRANT_RELEASE);
+ value = arb_gnt_read(ARB_CPU_INT_EN);
+ value &= ~(1 << lock);
+ arb_gnt_write(value, ARB_CPU_INT_EN);
+
+ spin_unlock_irqrestore(&arb->lock, flags);
+}
+
+int tegra_arb_mutex_lock_timeout(enum tegra_arb_module lock, int msecs)
+{
+ int ret;
+
+ if (!arb)
+ return -ENODEV;
+
+ if (arb->suspended) {
+ pr_err("device in suspend\n");
+ return -ETIMEDOUT;
+ }
+
+ mutex_lock(&arb->mutexes[lock]);
+ INIT_COMPLETION(arb->arb_gnt_complete[lock]);
+ request_arb_sem(lock);
+ ret = wait_for_completion_timeout(&arb->arb_gnt_complete[lock], msecs_to_jiffies(msecs));
+ if (ret == 0) {
+ pr_err("timed out.\n");
+ cancel_arb_sem(lock);
+ mutex_unlock(&arb->mutexes[lock]);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_arb_mutex_lock_timeout);
+
+int tegra_arb_mutex_unlock(enum tegra_arb_module lock)
+{
+ if (!arb)
+ return -ENODEV;
+
+ if (arb->suspended) {
+ pr_err("device in suspend\n");
+ return -ETIMEDOUT;
+ }
+
+ cancel_arb_sem(lock);
+ mutex_unlock(&arb->mutexes[lock]);
+ return 0;
+}
+EXPORT_SYMBOL(tegra_arb_mutex_unlock);
+
+static irqreturn_t arb_gnt_isr(int irq, void *dev_id)
+{
+ struct tegra_arb_dev *dev = dev_id;
+ unsigned long status;
+ u32 cpu_int_en;
+ unsigned int bit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&arb->lock, flags);
+
+ status = arb_sema_read(ARB_GRANT_STATUS);
+ pr_debug("%s: 0x%lx\n", __func__, status);
+
+ /* disable the arb semaphores which were signalled */
+ cpu_int_en = arb_gnt_read(ARB_CPU_INT_EN);
+ arb_gnt_write((cpu_int_en & ~(status & cpu_int_en)),
+ ARB_CPU_INT_EN);
+
+ status &= cpu_int_en;
+ for_each_set_bit(bit, &status, BITS_PER_LONG)
+ complete(&dev->arb_gnt_complete[bit]);
+
+ spin_unlock_irqrestore(&arb->lock, flags);
+ return IRQ_HANDLED;
+}
+
+int tegra_arb_suspend(void)
+{
+ unsigned long status = arb_sema_read(ARB_GRANT_STATUS);
+
+ if (WARN_ON(status != 0)) {
+ pr_err("%s: suspending while holding arbitration "
+ "semaphore: %08lx\n", __func__, status);
+ }
+ arb->suspended = true;
+
+ return status ? -EBUSY : 0;
+}
+
+int tegra_arb_resume(void)
+{
+ arb->suspended = false;
+ return 0;
+}
+
+static int __init tegra_arb_init(void)
+{
+ struct tegra_arb_dev *dev = NULL;
+ int err, i;
+
+ dev = kzalloc(sizeof(struct tegra_arb_dev), GFP_KERNEL);
+ if (dev == NULL) {
+ pr_err("%s: unable to alloc data struct.\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TEGRA_RPC_MAX_SEM; i++) {
+ mutex_init(&dev->mutexes[i]);
+ init_completion(&dev->arb_gnt_complete[i]);
+ }
+
+ dev->sema_base = IO_ADDRESS(TEGRA_ARB_SEMA_BASE);
+ if (!dev->sema_base) {
+ pr_err("%s: can't get arb sema_base\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dev->gnt_base = IO_ADDRESS(TEGRA_ARBGNT_ICTLR_BASE);
+ if (!dev->gnt_base) {
+ pr_err("%s: can't ioremap gnt_base\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dev->irq = INT_GNT_1;
+ err = request_irq(dev->irq, arb_gnt_isr, 0, "rpc-arbsema", dev);
+ if (err) {
+ pr_err("%s: request_irq(%d) failed(%d)\n", __func__,
+ dev->irq, err);
+ goto out;
+ }
+
+ spin_lock_init(&dev->lock);
+ arb = dev;
+
+ pr_info("%s: initialized\n", __func__);
+ return 0;
+
+out:
+ kfree(dev);
+ pr_err("%s: initialization failed.\n", __func__);
+ return err;
+}
+subsys_initcall(tegra_arb_init);
+
+MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c
index f609c6c11418..6302118a335b 100644
--- a/arch/arm/mach-tegra/board-ventana.c
+++ b/arch/arm/mach-tegra/board-ventana.c
@@ -209,6 +209,7 @@ static struct platform_device *ventana_devices[] __initdata = {
&pmu_device,
&tegra_udc_device,
&tegra_gart_device,
+ &tegra_aes_device,
&ventana_keys_device,
};
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 8059e039fc01..dac6bbbf0e2c 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -821,3 +821,24 @@ struct platform_device tegra_avp_device = {
.coherent_dma_mask = 0xffffffffULL,
},
};
+
+static struct resource tegra_aes_resources[] = {
+ {
+ .start = TEGRA_VDE_BASE,
+ .end = TEGRA_VDE_BASE + TEGRA_VDE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 tegra_aes_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device tegra_aes_device = {
+ .name = "tegra-aes",
+ .id = -1,
+ .resource = tegra_aes_resources,
+ .num_resources = ARRAY_SIZE(tegra_aes_resources),
+ .dev = {
+ .dma_mask = &tegra_aes_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index cbf141682989..1c547257a34f 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -59,5 +59,6 @@ extern struct platform_device tegra_spdif_device;
extern struct platform_device tegra_grhost_device;
extern struct platform_device tegra_spdif_device;
extern struct platform_device tegra_avp_device;
+extern struct platform_device tegra_aes_device;
#endif
diff --git a/arch/arm/mach-tegra/include/mach/arb_sema.h b/arch/arm/mach-tegra/include/mach/arb_sema.h
new file mode 100644
index 000000000000..374c5a913700
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/arb_sema.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-tegra/include/mach/arb_sema.h
+ *
+ * Hardware arbitration semaphore interface
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_TEGRA_ARB_SEMA_H
+#define __MACH_TEGRA_ARB_SEMA_H
+
+enum tegra_arb_module {
+ TEGRA_ARB_AES = 0,
+};
+
+int tegra_arb_mutex_lock_timeout(enum tegra_arb_module lock, int msecs);
+
+int tegra_arb_mutex_unlock(enum tegra_arb_module lock);
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 26f2363a8b3b..e7fe2788e92d 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -62,9 +62,15 @@
#define TEGRA_RES_SEMA_BASE 0x60001000
#define TEGRA_RES_SEMA_SIZE SZ_4K
+#define TEGRA_ARB_SEMA_BASE 0x60002000
+#define TEGRA_ARB_SEMA_SIZE SZ_4K
+
#define TEGRA_PRIMARY_ICTLR_BASE 0x60004000
#define TEGRA_PRIMARY_ICTLR_SIZE 64
+#define TEGRA_ARBGNT_ICTLR_BASE 0x60004040
+#define TEGRA_ARBGNT_ICTLR_SIZE 192
+
#define TEGRA_SECONDARY_ICTLR_BASE 0x60004100
#define TEGRA_SECONDARY_ICTLR_SIZE 64
@@ -119,6 +125,9 @@
#define TEGRA_EXCEPTION_VECTORS_BASE 0x6000F000
#define TEGRA_EXCEPTION_VECTORS_SIZE SZ_4K
+#define TEGRA_VDE_BASE 0x6001A000
+#define TEGRA_VDE_SIZE (SZ_8K + SZ_4K - SZ_256)
+
#define TEGRA_APB_MISC_BASE 0x70000000
#define TEGRA_APB_MISC_SIZE SZ_4K
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index eef598e456f1..3625b8091c76 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2035,6 +2035,7 @@ struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
CLK_DUPLICATE("cop", "tegra-avp", "cop"),
+ CLK_DUPLICATE("vde", "tegra-aes", "vde"),
};
#define CLK(dev, con, ck) \