diff options
Diffstat (limited to 'arch/arm/mach-tegra/irq.c')
-rw-r--r-- | arch/arm/mach-tegra/irq.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1fdbe708d43d..50a8dfb9a0cf 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 | |||
49 | static void (*gic_mask_irq)(unsigned int irq); | ||
50 | static void (*gic_unmask_irq)(unsigned int irq); | ||
51 | |||
52 | #define irq_to_ictlr(irq) (((irq)-32) >> 5) | ||
53 | static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE); | ||
54 | #define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100) | ||
55 | |||
56 | static 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 | |||
63 | static 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 | |||
72 | static int tegra_set_wake(unsigned int irq, unsigned int on) | ||
73 | { | ||
74 | return 0; | ||
75 | } | ||
76 | #endif | ||
77 | |||
78 | static 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 | |||
30 | void __init tegra_init_irq(void) | 87 | void __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 | ||
116 | static u32 cop_ier[PPI_NR]; | ||
117 | static u32 cpu_ier[PPI_NR]; | ||
118 | static u32 cpu_iep[PPI_NR]; | ||
119 | |||
120 | void 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 | |||
147 | void 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 | ||