blob: 280160aa018c86ae1c328ac09a20b1057d36935b [file] [log] [blame]
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -08001/* linux/arch/arm/mach-msm/irq.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/sched.h>
19#include <linux/interrupt.h>
20#include <linux/ptrace.h>
21#include <linux/timer.h>
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080022#include <linux/irq.h>
Russell Kingfced80c2008-09-06 12:10:45 +010023#include <linux/io.h>
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <asm/cacheflush.h>
26
Russell Kingfced80c2008-09-06 12:10:45 +010027#include <mach/hardware.h>
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080028
Russell Kinga09e64f2008-08-05 16:14:15 +010029#include <mach/msm_iomap.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#include <mach/fiq.h>
31
32#include "sirc.h"
33#include "smd_private.h"
34
35enum {
36 IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0,
37 IRQ_DEBUG_SLEEP_INT = 1U << 1,
38 IRQ_DEBUG_SLEEP_ABORT = 1U << 2,
39 IRQ_DEBUG_SLEEP = 1U << 3,
40 IRQ_DEBUG_SLEEP_REQUEST = 1U << 4,
41};
42static int msm_irq_debug_mask;
43module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080044
45#define VIC_REG(off) (MSM_VIC_BASE + (off))
46
47#define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */
48#define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */
49#define VIC_INT_EN0 VIC_REG(0x0010)
50#define VIC_INT_EN1 VIC_REG(0x0014)
51#define VIC_INT_ENCLEAR0 VIC_REG(0x0020)
52#define VIC_INT_ENCLEAR1 VIC_REG(0x0024)
53#define VIC_INT_ENSET0 VIC_REG(0x0030)
54#define VIC_INT_ENSET1 VIC_REG(0x0034)
55#define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */
56#define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */
57#define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */
58#define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */
59#define VIC_NO_PEND_VAL VIC_REG(0x0060)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060
61#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
62#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
63#define VIC_INT_MASTEREN VIC_REG(0x0068) /* 1: IRQ, 2: FIQ */
64#define VIC_CONFIG VIC_REG(0x006C) /* 1: USE SC VIC */
65#else
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080066#define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080067#define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068#define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */
69#endif
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080070#define VIC_IRQ_STATUS0 VIC_REG(0x0080)
71#define VIC_IRQ_STATUS1 VIC_REG(0x0084)
72#define VIC_FIQ_STATUS0 VIC_REG(0x0090)
73#define VIC_FIQ_STATUS1 VIC_REG(0x0094)
74#define VIC_RAW_STATUS0 VIC_REG(0x00A0)
75#define VIC_RAW_STATUS1 VIC_REG(0x00A4)
76#define VIC_INT_CLEAR0 VIC_REG(0x00B0)
77#define VIC_INT_CLEAR1 VIC_REG(0x00B4)
78#define VIC_SOFTINT0 VIC_REG(0x00C0)
79#define VIC_SOFTINT1 VIC_REG(0x00C4)
80#define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */
81#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */
82#define VIC_IRQ_VEC_WR VIC_REG(0x00D8)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083
84#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
85#define VIC_FIQ_VEC_RD VIC_REG(0x00DC)
86#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
87#define VIC_FIQ_VEC_WR VIC_REG(0x00E4)
88#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E8)
89#define VIC_IRQ_IN_STACK VIC_REG(0x00EC)
90#define VIC_FIQ_IN_SERVICE VIC_REG(0x00F0)
91#define VIC_FIQ_IN_STACK VIC_REG(0x00F4)
92#define VIC_TEST_BUS_SEL VIC_REG(0x00F8)
93#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC)
94#else
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080095#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0)
96#define VIC_IRQ_IN_STACK VIC_REG(0x00E4)
97#define VIC_TEST_BUS_SEL VIC_REG(0x00E8)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098#endif
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -080099
100#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
101#define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4))
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static uint32_t msm_irq_smsm_wake_enable[2];
104static struct {
105 uint32_t int_en[2];
106 uint32_t int_type;
107 uint32_t int_polarity;
108 uint32_t int_select;
109} msm_irq_shadow_reg[2];
110static uint32_t msm_irq_idle_disable[2];
111
112#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
113#define INT_INFO_SMSM_ID SMEM_SMSM_INT_INFO
114struct smsm_interrupt_info *smsm_int_info;
115#else
116#define INT_INFO_SMSM_ID SMEM_APPS_DEM_SLAVE_DATA
117struct msm_dem_slave_data *smsm_int_info;
118#endif
119
120
121#define SMSM_FAKE_IRQ (0xff)
122static uint8_t msm_irq_to_smsm[NR_MSM_IRQS + NR_SIRC_IRQS] = {
123 [INT_MDDI_EXT] = 1,
124 [INT_MDDI_PRI] = 2,
125 [INT_MDDI_CLIENT] = 3,
126 [INT_USB_OTG] = 4,
127
128 /* [INT_PWB_I2C] = 5 -- not usable */
129 [INT_SDC1_0] = 6,
130 [INT_SDC1_1] = 7,
131 [INT_SDC2_0] = 8,
132
133 [INT_SDC2_1] = 9,
134 [INT_ADSP_A9_A11] = 10,
135 [INT_UART1] = 11,
136 [INT_UART2] = 12,
137
138 [INT_UART3] = 13,
139 [INT_UART1_RX] = 14,
140 [INT_UART2_RX] = 15,
141 [INT_UART3_RX] = 16,
142
143 [INT_UART1DM_IRQ] = 17,
144 [INT_UART1DM_RX] = 18,
145 [INT_KEYSENSE] = 19,
146 [INT_AD_HSSD] = 20,
147
148 [INT_NAND_WR_ER_DONE] = 21,
149 [INT_NAND_OP_DONE] = 22,
150 [INT_TCHSCRN1] = 23,
151 [INT_TCHSCRN2] = 24,
152
153 [INT_TCHSCRN_SSBI] = 25,
154 [INT_USB_HS] = 26,
155 [INT_UART2DM_RX] = 27,
156 [INT_UART2DM_IRQ] = 28,
157
158 [INT_SDC4_1] = 29,
159 [INT_SDC4_0] = 30,
160 [INT_SDC3_1] = 31,
161 [INT_SDC3_0] = 32,
162
163 /* fake wakeup interrupts */
164 [INT_GPIO_GROUP1] = SMSM_FAKE_IRQ,
165 [INT_GPIO_GROUP2] = SMSM_FAKE_IRQ,
166 [INT_A9_M2A_0] = SMSM_FAKE_IRQ,
167 [INT_A9_M2A_1] = SMSM_FAKE_IRQ,
168 [INT_A9_M2A_5] = SMSM_FAKE_IRQ,
169 [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
170 [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
171 [INT_ADSP_A11] = SMSM_FAKE_IRQ,
172#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
173 [INT_SIRC_0] = SMSM_FAKE_IRQ,
174 [INT_SIRC_1] = SMSM_FAKE_IRQ,
175#endif
176};
177
178static void msm_irq_ack(unsigned int irq)
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800179{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
181 irq = 1 << (irq & 31);
182 writel(irq, reg);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800183}
184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185static void msm_irq_mask(unsigned int irq)
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800186{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
188 unsigned index = (irq >> 5) & 1;
189 uint32_t mask = 1UL << (irq & 31);
190 int smsm_irq = msm_irq_to_smsm[irq];
191
192 msm_irq_shadow_reg[index].int_en[0] &= ~mask;
193 writel(mask, reg);
194 if (smsm_irq == 0)
195 msm_irq_idle_disable[index] &= ~mask;
196 else {
197 mask = 1UL << (smsm_irq - 1);
198 msm_irq_smsm_wake_enable[0] &= ~mask;
199 }
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800200}
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202static void msm_irq_unmask(unsigned int irq)
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800203{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
205 unsigned index = (irq >> 5) & 1;
206 uint32_t mask = 1UL << (irq & 31);
207 int smsm_irq = msm_irq_to_smsm[irq];
208
209 msm_irq_shadow_reg[index].int_en[0] |= mask;
210 writel(mask, reg);
211
212 if (smsm_irq == 0)
213 msm_irq_idle_disable[index] |= mask;
214 else {
215 mask = 1UL << (smsm_irq - 1);
216 msm_irq_smsm_wake_enable[0] |= mask;
217 }
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800218}
219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220static int msm_irq_set_wake(unsigned int irq, unsigned int on)
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800221{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 unsigned index = (irq >> 5) & 1;
223 uint32_t mask = 1UL << (irq & 31);
224 int smsm_irq = msm_irq_to_smsm[irq];
225
226 if (smsm_irq == 0) {
227 printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
228 return -EINVAL;
229 }
230 if (on)
231 msm_irq_shadow_reg[index].int_en[1] |= mask;
232 else
233 msm_irq_shadow_reg[index].int_en[1] &= ~mask;
234
235 if (smsm_irq == SMSM_FAKE_IRQ)
236 return 0;
237
238 mask = 1UL << (smsm_irq - 1);
239 if (on)
240 msm_irq_smsm_wake_enable[1] |= mask;
241 else
242 msm_irq_smsm_wake_enable[1] &= ~mask;
243 return 0;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800244}
245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800247{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
249 void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
250 unsigned index = (irq >> 5) & 1;
251 int b = 1 << (irq & 31);
252 uint32_t polarity;
253 uint32_t type;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 polarity = msm_irq_shadow_reg[index].int_polarity;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800256 if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257 polarity |= b;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800258 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 polarity &= ~b;
260 writel(polarity, preg);
261 msm_irq_shadow_reg[index].int_polarity = polarity;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 type = msm_irq_shadow_reg[index].int_type;
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800264 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 type |= b;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100266 __irq_set_handler_locked(d->irq, handle_edge_irq);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800267 }
268 if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 type &= ~b;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100270 __irq_set_handler_locked(d->irq, handle_level_irq);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 writel(type, treg);
273 msm_irq_shadow_reg[index].int_type = type;
274 return 0;
275}
276
277int msm_irq_pending(void)
278{
279 return readl(VIC_IRQ_STATUS0) || readl(VIC_IRQ_STATUS1);
280}
281
282int msm_irq_idle_sleep_allowed(void)
283{
284 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST)
285 printk(KERN_INFO "msm_irq_idle_sleep_allowed: disable %x %x\n",
286 msm_irq_idle_disable[0], msm_irq_idle_disable[1]);
287 return !(msm_irq_idle_disable[0] || msm_irq_idle_disable[1] ||
288 !smsm_int_info);
289}
290
291/* If arm9_wake is set: pass control to the other core.
292 * If from_idle is not set: disable non-wakeup interrupts.
293 */
294void msm_irq_enter_sleep1(bool arm9_wake, int from_idle)
295{
296 if (!arm9_wake || !smsm_int_info)
297 return;
298 smsm_int_info->interrupt_mask = msm_irq_smsm_wake_enable[!from_idle];
299 smsm_int_info->pending_interrupts = 0;
300}
301
302int msm_irq_enter_sleep2(bool arm9_wake, int from_idle)
303{
304 int limit = 10;
305 uint32_t pending0, pending1;
306
307 if (from_idle && !arm9_wake)
308 return 0;
309
310 /* edge triggered interrupt may get lost if this mode is used */
311 WARN_ON_ONCE(!arm9_wake && !from_idle);
312
313 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
314 printk(KERN_INFO "msm_irq_enter_sleep change irq, pend %x %x\n",
315 readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
316 pending0 = readl(VIC_IRQ_STATUS0);
317 pending1 = readl(VIC_IRQ_STATUS1);
318 pending0 &= msm_irq_shadow_reg[0].int_en[!from_idle];
319 /* Clear INT_A9_M2A_5 since requesting sleep triggers it */
320 pending0 &= ~(1U << INT_A9_M2A_5);
321 pending1 &= msm_irq_shadow_reg[1].int_en[!from_idle];
322 if (pending0 || pending1) {
323 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
324 printk(KERN_INFO "msm_irq_enter_sleep2 abort %x %x\n",
325 pending0, pending1);
326 return -EAGAIN;
327 }
328
329 writel(0, VIC_INT_EN0);
330 writel(0, VIC_INT_EN1);
331
332 while (limit-- > 0) {
333 int pend_irq;
334 int irq = readl(VIC_IRQ_VEC_RD);
335 if (irq == -1)
336 break;
337 pend_irq = readl(VIC_IRQ_VEC_PEND_RD);
338 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
339 printk(KERN_INFO "msm_irq_enter_sleep cleared "
340 "int %d (%d)\n", irq, pend_irq);
341 }
342
343 if (arm9_wake) {
344 msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING);
345 msm_irq_ack(INT_A9_M2A_6);
346 writel(1U << INT_A9_M2A_6, VIC_INT_ENSET0);
347 } else {
348 writel(msm_irq_shadow_reg[0].int_en[1], VIC_INT_ENSET0);
349 writel(msm_irq_shadow_reg[1].int_en[1], VIC_INT_ENSET1);
350 }
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800351 return 0;
352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354void msm_irq_exit_sleep1(void)
355{
356 int i;
357
358 msm_irq_ack(INT_A9_M2A_6);
359 msm_irq_ack(INT_PWB_I2C);
360 for (i = 0; i < 2; i++) {
361 writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4);
362 writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4);
363 writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4);
364 writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT0 + i * 4);
365 }
366 writel(3, VIC_INT_MASTEREN);
367 if (!smsm_int_info) {
368 printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
369 return;
370 }
371 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
372 printk(KERN_INFO "msm_irq_exit_sleep1 %x %x %x now %x %x\n",
373 smsm_int_info->interrupt_mask,
374 smsm_int_info->pending_interrupts,
375 smsm_int_info->wakeup_reason,
376 readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
377}
378
379void msm_irq_exit_sleep2(void)
380{
381 int i;
382 uint32_t pending;
383
384 if (!smsm_int_info) {
385 printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
386 return;
387 }
388 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
389 printk(KERN_INFO "msm_irq_exit_sleep2 %x %x %x now %x %x\n",
390 smsm_int_info->interrupt_mask,
391 smsm_int_info->pending_interrupts,
392 smsm_int_info->wakeup_reason,
393 readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
394 pending = smsm_int_info->pending_interrupts;
395 for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) {
396 unsigned reg_offset = (i & 32) ? 4 : 0;
397 uint32_t reg_mask = 1UL << (i & 31);
398 int smsm_irq = msm_irq_to_smsm[i];
399 uint32_t smsm_mask;
400 if (smsm_irq == 0)
401 continue;
402 smsm_mask = 1U << (smsm_irq - 1);
403 if (!(pending & smsm_mask))
404 continue;
405 pending &= ~smsm_mask;
406 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
407 printk(KERN_INFO "msm_irq_exit_sleep2: irq %d "
408 "still pending %x now %x %x\n", i, pending,
409 readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
410#if 0 /* debug intetrrupt trigger */
411 if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
412 writel(reg_mask, VIC_INT_CLEAR0 + reg_offset);
413#endif
414 if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
415 continue;
416 writel(reg_mask, VIC_SOFTINT0 + reg_offset);
417 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER)
418 printk(KERN_INFO "msm_irq_exit_sleep2: irq %d need "
419 "trigger, now %x %x\n", i,
420 readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
421 }
422}
423
424void msm_irq_exit_sleep3(void)
425{
426 if (!smsm_int_info) {
427 printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
428 return;
429 }
430 if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
431 printk(KERN_INFO "msm_irq_exit_sleep3 %x %x %x now %x %x "
432 "state %x\n", smsm_int_info->interrupt_mask,
433 smsm_int_info->pending_interrupts,
434 smsm_int_info->wakeup_reason, readl(VIC_IRQ_STATUS0),
435 readl(VIC_IRQ_STATUS1),
436 smsm_get_state(SMSM_STATE_MODEM));
437}
438
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800439static struct irq_chip msm_irq_chip = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 .name = "msm",
441 .disable = msm_irq_mask,
442 .ack = msm_irq_ack,
443 .mask = msm_irq_mask,
444 .unmask = msm_irq_unmask,
445 .set_wake = msm_irq_set_wake,
446 .set_type = msm_irq_set_type,
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800447};
448
449void __init msm_init_irq(void)
450{
451 unsigned n;
452
453 /* select level interrupts */
454 writel(0, VIC_INT_TYPE0);
455 writel(0, VIC_INT_TYPE1);
456
457 /* select highlevel interrupts */
458 writel(0, VIC_INT_POLARITY0);
459 writel(0, VIC_INT_POLARITY1);
460
461 /* select IRQ for all INTs */
462 writel(0, VIC_INT_SELECT0);
463 writel(0, VIC_INT_SELECT1);
464
465 /* disable all INTs */
466 writel(0, VIC_INT_EN0);
467 writel(0, VIC_INT_EN1);
468
469 /* don't use 1136 vic */
470 writel(0, VIC_CONFIG);
471
472 /* enable interrupt controller */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 writel(3, VIC_INT_MASTEREN);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800474
475 for (n = 0; n < NR_MSM_IRQS; n++) {
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +0100476 irq_set_chip_and_handler(n, &msm_irq_chip, handle_level_irq);
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800477 set_irq_flags(n, IRQF_VALID);
478 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479
480 msm_init_sirc();
Arve Hjønnevåg3e4ea372007-11-26 04:11:58 -0800481}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482
483static int __init msm_init_irq_late(void)
484{
485 smsm_int_info = smem_alloc(INT_INFO_SMSM_ID, sizeof(*smsm_int_info));
486 if (!smsm_int_info)
487 pr_err("set_wakeup_mask NO INT_INFO (%d)\n", INT_INFO_SMSM_ID);
488 return 0;
489}
490late_initcall(msm_init_irq_late);
491
492#if defined(CONFIG_MSM_FIQ_SUPPORT)
493void msm_trigger_irq(int irq)
494{
495 void __iomem *reg = VIC_SOFTINT0 + ((irq & 32) ? 4 : 0);
496 uint32_t mask = 1UL << (irq & 31);
497 writel(mask, reg);
498}
499
500void msm_fiq_enable(int irq)
501{
502 unsigned long flags;
503 local_irq_save(flags);
504 irq_desc[irq].chip->unmask(irq);
505 local_irq_restore(flags);
506}
507
508void msm_fiq_disable(int irq)
509{
510 unsigned long flags;
511 local_irq_save(flags);
512 irq_desc[irq].chip->mask(irq);
513 local_irq_restore(flags);
514}
515
516static void _msm_fiq_select(int irq)
517{
518 void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0);
519 unsigned index = (irq >> 5) & 1;
520 uint32_t mask = 1UL << (irq & 31);
521 unsigned long flags;
522
523 local_irq_save(flags);
524 msm_irq_shadow_reg[index].int_select |= mask;
525 writel(msm_irq_shadow_reg[index].int_select, reg);
526 local_irq_restore(flags);
527}
528
529static void _msm_fiq_unselect(int irq)
530{
531 void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0);
532 unsigned index = (irq >> 5) & 1;
533 uint32_t mask = 1UL << (irq & 31);
534 unsigned long flags;
535
536 local_irq_save(flags);
537 msm_irq_shadow_reg[index].int_select &= (!mask);
538 writel(msm_irq_shadow_reg[index].int_select, reg);
539 local_irq_restore(flags);
540}
541
542void msm_fiq_select(int irq)
543{
544 if (irq < FIRST_SIRC_IRQ)
545 _msm_fiq_select(irq);
546 else if (irq < FIRST_GPIO_IRQ)
547 sirc_fiq_select(irq, true);
548 else
549 pr_err("unsupported fiq %d", irq);
550}
551
552void msm_fiq_unselect(int irq)
553{
554 if (irq < FIRST_SIRC_IRQ)
555 _msm_fiq_unselect(irq);
556 else if (irq < FIRST_GPIO_IRQ)
557 sirc_fiq_select(irq, false);
558 else
559 pr_err("unsupported fiq %d", irq);
560}
561
562/* set_fiq_handler originally from arch/arm/kernel/fiq.c */
563static void set_fiq_handler(void *start, unsigned int length)
564{
565 memcpy((void *)0xffff001c, start, length);
566 flush_icache_range(0xffff001c, 0xffff001c + length);
567 if (!vectors_high())
568 flush_icache_range(0x1c, 0x1c + length);
569}
570
571extern unsigned char fiq_glue, fiq_glue_end;
572
573static void (*fiq_func)(void *data, void *regs, void *svc_sp);
574static void *fiq_data;
575static void *fiq_stack;
576
577void fiq_glue_setup(void *func, void *data, void *sp);
578
579int msm_fiq_set_handler(void (*func)(void *data, void *regs, void *svc_sp),
580 void *data)
581{
582 unsigned long flags;
583 int ret = -ENOMEM;
584
585 if (!fiq_stack)
586 fiq_stack = kzalloc(THREAD_SIZE, GFP_KERNEL);
587 if (!fiq_stack)
588 return -ENOMEM;
589
590 local_irq_save(flags);
591 if (fiq_func == 0) {
592 fiq_func = func;
593 fiq_data = data;
594 fiq_glue_setup(func, data, fiq_stack + THREAD_START_SP);
595 set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue));
596 ret = 0;
597 }
598 local_irq_restore(flags);
599 return ret;
600}
601
602void msm_fiq_exit_sleep(void)
603{
604 if (fiq_stack)
605 fiq_glue_setup(fiq_func, fiq_data, fiq_stack + THREAD_START_SP);
606}
607#endif