diff options
author | Scott Williams <scwilliams@nvidia.com> | 2011-07-12 18:05:12 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:46:54 -0800 |
commit | 108c397e52eed8e8f6fa510cdba20d0c7665de21 (patch) | |
tree | 813f43fda7ad5859e920f6d89eb6f0d71bb1f3bb | |
parent | 27a435eb62ef122692e904cbd2959ac191bc43cc (diff) |
ARM: tegra: Add Tegra GIC extensions
Implement extensions to the standard ARM GIC API for Tegra3 power management.
Change-Id: If8b2ce2b366e48bb5ca82d3de2acab1fd0a81bb9
Signed-off-by: Scott Williams <scwilliams@nvidia.com>
Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com>
Rebase-Id: Rd7527cd57edf054c871f5d04d7e9185643f79843
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t2.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-tegra/gic.c | 129 | ||||
-rw-r--r-- | arch/arm/mach-tegra/gic.h | 49 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/irqs.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm.h | 2 |
7 files changed, 192 insertions, 13 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 9e909b6dbd8e..baac685f590a 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -15,6 +15,7 @@ obj-y += delay.o obj-y += powergate.o obj-y += pm.o obj-$(CONFIG_PM_SLEEP) += pm-irq.o +obj-y += gic.o obj-y += sleep.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t2.o obj-y += fuse.o diff --git a/arch/arm/mach-tegra/cpuidle-t2.c b/arch/arm/mach-tegra/cpuidle-t2.c index 326d4e8ec215..c4f648e41eb2 100644 --- a/arch/arm/mach-tegra/cpuidle-t2.c +++ b/arch/arm/mach-tegra/cpuidle-t2.c @@ -45,6 +45,7 @@ #include <mach/irqs.h> #include "cpuidle.h" +#include "gic.h" #include "pm.h" #include "sleep.h" @@ -187,8 +188,10 @@ static int tegra2_idle_lp2_last(struct cpuidle_device *dev, if (tegra_idle_lp2_last(sleep_time, 0) == 0) sleep_completed = true; - else - idle_stats.lp2_int_count[tegra_pending_interrupt()]++; + else { + int irq = tegra_gic_pending_interrupt(); + idle_stats.lp2_int_count[irq]++; + } } for_each_online_cpu(i) { diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h index ae3386139d38..5d0c3d695342 100644 --- a/arch/arm/mach-tegra/cpuidle.h +++ b/arch/arm/mach-tegra/cpuidle.h @@ -75,15 +75,6 @@ static inline int tegra_lp2_debug_show(struct seq_file *s, void *data) } #endif -static inline int tegra_pending_interrupt(void) -{ - void __iomem *gic_cpu = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100); - u32 reg = readl(gic_cpu + 0x18); - reg &= 0x3FF; - - return reg; -} - #ifdef CONFIG_CPU_IDLE void tegra_lp2_in_idle(bool enable); #else diff --git a/arch/arm/mach-tegra/gic.c b/arch/arm/mach-tegra/gic.c new file mode 100644 index 000000000000..50cecc4eed64 --- /dev/null +++ b/arch/arm/mach-tegra/gic.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010-2011, 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/kernel.h> +#include <linux/cpumask.h> /* Required by asm/hardware/gic.h */ +#include <linux/io.h> +#include <linux/irqnr.h> + +#include <asm/hardware/gic.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#include "gic.h" +#include "pm.h" + +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) +static void __iomem *gic_cpu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100); + +void tegra_gic_cpu_disable(void) +{ + writel(0, gic_cpu_base + GIC_CPU_CTRL); +} + +void tegra_gic_cpu_enable(void) +{ + writel(1, gic_cpu_base + GIC_CPU_CTRL); +} + +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + +void tegra_gic_pass_through_disable(void) +{ + u32 val = readl(gic_cpu_base + GIC_CPU_CTRL); + val |= 2; /* enableNS = disable GIC pass through */ + writel(val, gic_cpu_base + GIC_CPU_CTRL); +} + +#endif +#endif + +#if defined(CONFIG_PM_SLEEP) + +int tegra_gic_pending_interrupt(void) +{ + u32 irq = readl(gic_cpu_base + GIC_CPU_HIGHPRI); + irq &= 0x3FF; + + return irq; +} + +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + +static void __iomem *gic_dist_base = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE); +static u32 gic_affinity[INT_GIC_NR/4]; + +void tegra_gic_dist_disable(void) +{ + writel(0, gic_dist_base + GIC_DIST_CTRL); +} + +void tegra_gic_dist_enable(void) +{ + writel(1, gic_dist_base + GIC_DIST_CTRL); +} + +void tegra_gic_disable_affinity(void) +{ + unsigned int i; + + BUG_ON(is_lp_cluster()); + + /* The GIC distributor TARGET register is one byte per IRQ. */ + for (i = 32; i < INT_GIC_NR; i += 4) { + /* Save the affinity. */ + gic_affinity[i/4] = __raw_readl(gic_dist_base + + GIC_DIST_TARGET + i); + + /* Force this interrupt to CPU0. */ + __raw_writel(0x01010101, gic_dist_base + GIC_DIST_TARGET + i); + } + + wmb(); +} + +void tegra_gic_restore_affinity(void) +{ + unsigned int i; + + BUG_ON(is_lp_cluster()); + + /* The GIC distributor TARGET register is one byte per IRQ. */ + for (i = 32; i < INT_GIC_NR; i += 4) { +#ifdef CONFIG_BUG + u32 reg = __raw_readl(gic_dist_base + GIC_DIST_TARGET + i); + if (reg & 0xFEFEFEFE) + panic("GIC affinity changed!"); +#endif + /* Restore this interrupt's affinity. */ + __raw_writel(gic_affinity[i/4], gic_dist_base + + GIC_DIST_TARGET + i); + } + + wmb(); +} + +void tegra_gic_affinity_to_cpu0(void) +{ + unsigned int i; + + BUG_ON(is_lp_cluster()); + + for (i = 32; i < INT_GIC_NR; i += 4) + __raw_writel(0x01010101, gic_dist_base + GIC_DIST_TARGET + i); + wmb(); +} +#endif +#endif diff --git a/arch/arm/mach-tegra/gic.h b/arch/arm/mach-tegra/gic.h new file mode 100644 index 000000000000..94dab6e581af --- /dev/null +++ b/arch/arm/mach-tegra/gic.h @@ -0,0 +1,49 @@ +/* + * arch/arm/mach-tegra/include/mach/gic.h + * + * Copyright (C) 2010-2011 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. + * + */ + +#ifndef _MACH_TEGRA_GIC_H_ +#define _MACH_TEGRA_GIC_H_ + +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) + +void tegra_gic_cpu_disable(void); +void tegra_gic_cpu_enable(void); + +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + +void tegra_gic_pass_through_disable(void); + +#endif +#endif + + +#if defined(CONFIG_PM_SLEEP) + +int tegra_gic_pending_interrupt(void); + +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + +void tegra_gic_dist_disable(void); +void tegra_gic_dist_enable(void); + +void tegra_gic_disable_affinity(void); +void tegra_gic_restore_affinity(void); +void tegra_gic_affinity_to_cpu0(void); + +#endif +#endif + +#endif /* _MACH_TEGRA_GIC_H_ */ diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h index e7c1ad3b7991..d25a0aa28862 100644 --- a/arch/arm/mach-tegra/include/mach/irqs.h +++ b/arch/arm/mach-tegra/include/mach/irqs.h @@ -166,7 +166,9 @@ #define INT_QUAD_RES_30 (INT_QUAD_BASE + 30) #define INT_QUAD_RES_31 (INT_QUAD_BASE + 31) -#define INT_MAIN_NR (INT_QUAD_BASE + 32 - INT_PRI_BASE) +#define INT_GIC_NR (INT_QUAD_BASE + 32) + +#define INT_MAIN_NR (INT_GIC_NR - INT_PRI_BASE) #define INT_SYNCPT_THRESH_BASE (INT_QUAD_BASE + 32) #define INT_SYNCPT_THRESH_NR 32 @@ -352,7 +354,9 @@ #define INT_QUINT_RES_30 (INT_QUINT_BASE + 30) #define INT_QUINT_RES_31 (INT_QUINT_BASE + 31) -#define INT_MAIN_NR (INT_QUINT_BASE + 32 - INT_PRI_BASE) +#define INT_GIC_NR (INT_QUINT_BASE + 32) + +#define INT_MAIN_NR (INT_GIC_NR - INT_PRI_BASE) #define INT_SYNCPT_THRESH_BASE (INT_QUINT_BASE + 32) #define INT_SYNCPT_THRESH_NR 32 diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h index ff8480bc76ca..9a78f620f571 100644 --- a/arch/arm/mach-tegra/pm.h +++ b/arch/arm/mach-tegra/pm.h @@ -23,6 +23,8 @@ #define _MACH_TEGRA_PM_H_ #include <linux/mutex.h> +#include <linux/init.h> +#include <linux/errno.h> enum tegra_suspend_mode { TEGRA_SUSPEND_NONE = 0, |