diff options
author | Dima Zavin <dima@android.com> | 2010-12-14 14:12:05 -0800 |
---|---|---|
committer | Dima Zavin <dima@android.com> | 2010-12-14 14:12:05 -0800 |
commit | 2da4db5bffe757188b0a06235e5e68505a5c20c4 (patch) | |
tree | 23bda60cab591c6f065ec58d11d84a2e0335371b /arch/arm | |
parent | 98bf149e45c7a6e93d2c09ff789f1e7c970ec9a7 (diff) | |
parent | 8fc88f1863d8130419ce3f10ff4e50e013425101 (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/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/arb_sema.c | 242 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-ventana.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/devices.c | 21 | ||||
-rw-r--r-- | arch/arm/mach-tegra/devices.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/arb_sema.h | 34 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/iomap.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 1 |
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) \ |