aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-04-05 23:30:59 -0400
committerColin Cross <ccross@android.com>2010-10-21 21:11:31 -0400
commit460907bc26f5565aced3cf35a10e3579c671ef50 (patch)
tree8e13848797444538c38e749d6539657319bcb0ce /arch/arm
parent8726e4f50e3f445601c19a851c62586f5dc7dd49 (diff)
[ARM] tegra: add suspend and mirror irqs to legacy controller
mirror IRQ enable and disable operations on the legacy PPI system interrupt controller, since the legacy controller is responsible for responding to wakeup interrupts when the CPU is in LP2 idle mode save the irq controller state on suspend and restore on resume Signed-off-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-tegra/irq.c137
2 files changed, 139 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index 20f640edaa0..71bbf342295 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -25,6 +25,7 @@
25 25
26#define IRQ_LOCALTIMER 29 26#define IRQ_LOCALTIMER 29
27 27
28#ifdef CONFIG_ARCH_TEGRA_2x_SOC
28/* Primary Interrupt Controller */ 29/* Primary Interrupt Controller */
29#define INT_PRI_BASE (INT_GIC_BASE + 32) 30#define INT_PRI_BASE (INT_GIC_BASE + 32)
30#define INT_TMR1 (INT_PRI_BASE + 0) 31#define INT_TMR1 (INT_PRI_BASE + 0)
@@ -169,5 +170,6 @@
169#define INT_GPIO_NR (28 * 8) 170#define INT_GPIO_NR (28 * 8)
170 171
171#define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR) 172#define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
173#endif
172 174
173#endif 175#endif
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 1fdbe708d43..50a8dfb9a0c 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -4,6 +4,8 @@
4 * Author: 4 * Author:
5 * Colin Cross <ccross@google.com> 5 * Colin Cross <ccross@google.com>
6 * 6 *
7 * Copyright (C) 2010, NVIDIA Corporation
8 *
7 * This software is licensed under the terms of the GNU General Public 9 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and 10 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms. 11 * may be copied, distributed, and modified under those terms.
@@ -27,8 +29,143 @@
27 29
28#include "board.h" 30#include "board.h"
29 31
32#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
33#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
34#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
35
36#define APBDMA_IRQ_STA_CPU 0x14
37#define APBDMA_IRQ_MASK_SET 0x20
38#define APBDMA_IRQ_MASK_CLR 0x24
39
40#define ICTLR_CPU_IER 0x20
41#define ICTLR_CPU_IER_SET 0x24
42#define ICTLR_CPU_IER_CLR 0x28
43#define ICTLR_CPU_IEP_CLASS 0x2c
44#define ICTLR_COP_IER 0x30
45#define ICTLR_COP_IER_SET 0x34
46#define ICTLR_COP_IER_CLR 0x38
47#define ICTLR_COP_IEP_CLASS 0x3c
48
49static void (*gic_mask_irq)(unsigned int irq);
50static void (*gic_unmask_irq)(unsigned int irq);
51
52#define irq_to_ictlr(irq) (((irq)-32) >> 5)
53static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
54#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
55
56static void tegra_mask(unsigned int irq)
57{
58 void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
59 gic_mask_irq(irq);
60 writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR);
61}
62
63static void tegra_unmask(unsigned int irq)
64{
65 void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
66 gic_unmask_irq(irq);
67 writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET);
68}
69
70#ifdef CONFIG_PM
71
72static int tegra_set_wake(unsigned int irq, unsigned int on)
73{
74 return 0;
75}
76#endif
77
78static struct irq_chip tegra_irq = {
79 .name = "PPI",
80 .mask = tegra_mask,
81 .unmask = tegra_unmask,
82#ifdef CONFIG_PM
83 .set_wake = tegra_set_wake,
84#endif
85};
86
30void __init tegra_init_irq(void) 87void __init tegra_init_irq(void)
31{ 88{
89 struct irq_chip *gic;
90 unsigned int i;
91
92 for (i = 0; i < PPI_NR; i++) {
93 writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
94 writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
95 }
96
32 gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29); 97 gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29);
33 gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); 98 gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
99
100 gic = get_irq_chip(29);
101 gic_unmask_irq = gic->unmask;
102 gic_mask_irq = gic->mask;
103 tegra_irq.ack = gic->ack;
104#ifdef CONFIG_SMP
105 tegra_irq.set_affinity = gic->set_affinity;
106#endif
107
108 for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
109 set_irq_chip(i, &tegra_irq);
110 set_irq_handler(i, handle_level_irq);
111 set_irq_flags(i, IRQF_VALID);
112 }
113}
114
115#ifdef CONFIG_PM
116static u32 cop_ier[PPI_NR];
117static u32 cpu_ier[PPI_NR];
118static u32 cpu_iep[PPI_NR];
119
120void tegra_irq_suspend(void)
121{
122 unsigned long flags;
123 int i;
124
125 for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
126 struct irq_desc *desc = irq_to_desc(i);
127 if (!desc)
128 continue;
129 if (desc->status & IRQ_WAKEUP) {
130 pr_debug("irq %d is wakeup\n", i);
131 continue;
132 }
133 disable_irq(i);
134 }
135
136 local_irq_save(flags);
137 for (i = 0; i < PPI_NR; i++) {
138 void __iomem *ictlr = ictlr_to_virt(i);
139 cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
140 cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
141 cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
142 writel(~0, ictlr + ICTLR_COP_IER_CLR);
143 }
144 local_irq_restore(flags);
145}
146
147void tegra_irq_resume(void)
148{
149 unsigned long flags;
150 int i;
151
152 local_irq_save(flags);
153 for (i = 0; i < PPI_NR; i++) {
154 void __iomem *ictlr = ictlr_to_virt(i);
155 writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
156 writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
157 writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
158 writel(0, ictlr + ICTLR_COP_IEP_CLASS);
159 writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
160 writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
161 }
162 local_irq_restore(flags);
163
164 for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
165 struct irq_desc *desc = irq_to_desc(i);
166 if (!desc || (desc->status & IRQ_WAKEUP))
167 continue;
168 enable_irq(i);
169 }
34} 170}
171#endif