aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/gic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/gic.c')
-rw-r--r--arch/arm/mach-tegra/gic.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/gic.c b/arch/arm/mach-tegra/gic.c
new file mode 100644
index 00000000000..6c2dc940675
--- /dev/null
+++ b/arch/arm/mach-tegra/gic.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright (C) 2010-2012, NVIDIA Corporation
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/cpumask.h> /* Required by asm/hardware/gic.h */
17#include <linux/io.h>
18#include <linux/irqnr.h>
19
20#include <asm/hardware/gic.h>
21
22#include <mach/iomap.h>
23#include <mach/irqs.h>
24
25#include "gic.h"
26#include "pm.h"
27
28#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
29static void __iomem *gic_cpu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100);
30
31void tegra_gic_cpu_disable(void)
32{
33 writel(0, gic_cpu_base + GIC_CPU_CTRL);
34}
35
36void tegra_gic_cpu_enable(void)
37{
38 writel(1, gic_cpu_base + GIC_CPU_CTRL);
39}
40
41#ifndef CONFIG_ARCH_TEGRA_2x_SOC
42
43void tegra_gic_pass_through_disable(void)
44{
45 u32 val = readl(gic_cpu_base + GIC_CPU_CTRL);
46 val |= 2; /* enableNS = disable GIC pass through */
47 writel(val, gic_cpu_base + GIC_CPU_CTRL);
48}
49
50#endif
51#endif
52
53#if defined(CONFIG_PM_SLEEP)
54
55int tegra_gic_pending_interrupt(void)
56{
57 u32 irq = readl(gic_cpu_base + GIC_CPU_HIGHPRI);
58 irq &= 0x3FF;
59
60 return irq;
61}
62
63#ifndef CONFIG_ARCH_TEGRA_2x_SOC
64
65static void __iomem *gic_dist_base = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
66static u32 gic_affinity[INT_GIC_NR/4];
67
68void tegra_gic_dist_disable(void)
69{
70 writel(0, gic_dist_base + GIC_DIST_CTRL);
71}
72
73void tegra_gic_dist_enable(void)
74{
75 writel(1, gic_dist_base + GIC_DIST_CTRL);
76}
77
78void tegra_gic_disable_affinity(void)
79{
80 unsigned int i;
81
82 BUG_ON(is_lp_cluster());
83
84 /* The GIC distributor TARGET register is one byte per IRQ. */
85 for (i = 32; i < INT_GIC_NR; i += 4) {
86 /* Save the affinity. */
87 gic_affinity[i/4] = __raw_readl(gic_dist_base +
88 GIC_DIST_TARGET + i);
89
90 /* Force this interrupt to CPU0. */
91 __raw_writel(0x01010101, gic_dist_base + GIC_DIST_TARGET + i);
92 }
93
94 wmb();
95}
96
97void tegra_gic_restore_affinity(void)
98{
99 unsigned int i;
100
101 BUG_ON(is_lp_cluster());
102
103 /* The GIC distributor TARGET register is one byte per IRQ. */
104 for (i = 32; i < INT_GIC_NR; i += 4) {
105#ifdef CONFIG_BUG
106 u32 reg = __raw_readl(gic_dist_base + GIC_DIST_TARGET + i);
107 if (reg & 0xFEFEFEFE)
108 panic("GIC affinity changed!");
109#endif
110 /* Restore this interrupt's affinity. */
111 __raw_writel(gic_affinity[i/4], gic_dist_base +
112 GIC_DIST_TARGET + i);
113 }
114
115 wmb();
116}
117
118void tegra_gic_affinity_to_cpu0(void)
119{
120 unsigned int i;
121
122 BUG_ON(is_lp_cluster());
123
124 for (i = 32; i < INT_GIC_NR; i += 4)
125 __raw_writel(0x01010101, gic_dist_base + GIC_DIST_TARGET + i);
126 wmb();
127}
128#endif
129#endif
130
131void __init tegra_gic_init(void)
132{
133 gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
134 IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
135}