1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by James Espinoza
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #include "avic-imx31.h"
28 #define avic ((unsigned long * const)AVIC_BASE_ADDR)
29 #define INTCNTL (0x000 / sizeof (unsigned long)) /* 000h */
30 #define NIMASK (0x004 / sizeof (unsigned long)) /* 004h */
31 #define INTENNUM (0x008 / sizeof (unsigned long)) /* 008h */
32 #define INTDISNUM (0x00c / sizeof (unsigned long)) /* 00Ch */
33 #define INTENABLE (0x010 / sizeof (unsigned long)) /* 010h H,L */
34 #define INTTYPE (0x018 / sizeof (unsigned long)) /* 018h H,L */
35 #define NIPRIORITY (0x020 / sizeof (unsigned long)) /* 020h 7-0 */
36 #define NIVECSR (0x040 / sizeof (unsigned long)) /* 040h */
37 #define FIVECSR (0x044 / sizeof (unsigned long)) /* 044h */
38 #define INTSRC (0x048 / sizeof (unsigned long)) /* 048h H,L */
39 #define INTFRC (0x050 / sizeof (unsigned long)) /* 050h H,L */
40 #define NIPND (0x058 / sizeof (unsigned long)) /* 058h H,L */
41 #define FIPND (0x060 / sizeof (unsigned long)) /* 060h H,L */
42 #define VECTOR (0x100 / sizeof (unsigned long)) /* 100h */
44 static const char * const avic_int_names
[64] =
46 "RESERVED0", "RESERVED1", "RESERVED2", "I2C3",
47 "I2C2", "MPEG4_ENCODER", "RTIC", "FIR",
48 "MMC/SDHC2", "MMC/SDHC1", "I2C1", "SSI2",
49 "SSI1", "CSPI2", "CSPI1", "ATA",
50 "MBX", "CSPI3", "UART3", "IIM",
51 "SIM1", "SIM2", "RNGA", "EVTMON",
52 "KPP", "RTC", "PWN", "EPIT2",
53 "EPIT1", "GPT", "PWR_FAIL", "CCM_DVFS",
54 "UART2", "NANDFC", "SDMA", "USB_HOST1",
55 "USB_HOST2", "USB_OTG", "RESERVED3", "MSHC1",
56 "MSHC2", "IPU_ERR", "IPU", "RESERVED4",
57 "RESERVED5", "UART1", "UART4", "UART5",
58 "ETC_IRQ", "SCC_SCM", "SCC_SMN", "GPIO2",
59 "GPIO1", "CCM_CLK", "PCMCIA", "WDOG",
60 "GPIO3", "RESERVED6", "EXT_PWMG", "EXT_TEMP",
61 "EXT_SENS1", "EXT_SENS2", "EXT_WDOG", "EXT_TV"
70 "mrs %0, cpsr \n" /* Mask core IRQ/FIQ */
71 "orr %0, %0, #0xc0 \n"
73 "and %0, %0, #0x1f \n" /* Get mode bits */
77 offset
= mode
== 0x11 ? (long)avic
[FIVECSR
] : ((long)avic
[NIVECSR
] >> 16);
79 panicf("Unhandled %s %d: %s",
80 mode
== 0x11 ? "FIQ" : "IRQ", offset
,
81 offset
>= 0 ? avic_int_names
[offset
] : "<Unknown>");
86 void __attribute__((interrupt("IRQ"))) irq_handler(void)
88 int offset
= (long)avic
[NIVECSR
] >> 16;
92 /* This is called occasionally for some unknown reason even with the
93 * avic enabled but returning normally appears to cause no harm. The
94 * KPP and ATA seem to have a part in it (common but multiplexed pins
95 * that can interfere). It will be investigated more thoroughly but
96 * for now it is simply an occasional irritant. */
100 disable_interrupt(IRQ_FIQ_STATUS
);
101 panicf("Unhandled IRQ %d in irq_handler: %s", offset
,
102 offset
>= 0 ? avic_int_names
[offset
] : "<Unknown>");
106 /* Accoring to section 9.3.5 of the UM, the AVIC doesn't accelerate
107 * fast interrupts and they must be dispatched */
108 void __attribute__((naked
)) fiq_handler(void)
111 "mov r10, #0x68000000 \n" /* load AVIC base address */
112 "ldr r9, [r10, #0x44] \n" /* read FIVECSR of AVIC */
113 "add r10, r10, #0x100 \n" /* move pointer to base of VECTOR table */
114 "ldr r8, [r10, r9, lsl #2] \n" /* read FIQ vector from VECTOR table */
115 "bx r8 \n" /* jump to FIQ service routine */
123 /* Disable all interrupts and set to unhandled */
124 avic_disable_int(INT_ALL
);
126 /* Reset AVIC control */
129 /* Init all interrupts to type IRQ */
130 avic_set_int_type(INT_ALL
, INT_TYPE_IRQ
);
132 /* Set all normal to lowest priority */
133 for (i
= 0; i
< 8; i
++)
134 avic
[NIPRIORITY
+ i
] = 0;
136 /* Set NM bit to enable VIC. Mask fast interrupts. Core arbiter rise
137 * for normal interrupts (for lowest latency). */
138 avic
[INTCNTL
] |= AVIC_INTCNTL_NM
| AVIC_INTCNTL_FIDIS
|
141 /* Enable VE bit in CP15 Control reg to enable VIC */
143 "mrc p15, 0, r0, c1, c0, 0 \n"
144 "orr r0, r0, #(1 << 24) \n"
145 "mcr p15, 0, r0, c1, c0, 0 \n"
148 /* Enable normal interrupts at all priorities */
149 avic
[NIMASK
] = AVIC_NIL_ENABLE
;
152 void avic_set_int_priority(enum IMX31_INT_LIST ints
,
153 unsigned long ni_priority
)
155 volatile unsigned long * const reg
= &avic
[NIPRIORITY
+ 7 - (ints
>> 3)];
156 unsigned int shift
= (ints
& 0x7) << 2;
157 unsigned long mask
= 0xful
<< shift
;
158 *reg
= (*reg
& ~mask
) | ((ni_priority
<< shift
) & mask
);
161 void avic_enable_int(enum IMX31_INT_LIST ints
, enum INT_TYPE intstype
,
162 unsigned long ni_priority
, void (*handler
)(void))
164 int oldstatus
= disable_interrupt_save(IRQ_FIQ_STATUS
);
166 if (ints
!= INT_ALL
) /* No mass-enable allowed */
168 avic_set_int_type(ints
, intstype
);
169 avic
[VECTOR
+ ints
] = (unsigned long)handler
;
170 avic
[INTENNUM
] = ints
;
171 avic_set_int_priority(ints
, ni_priority
);
174 restore_interrupt(oldstatus
);
177 void avic_disable_int(enum IMX31_INT_LIST ints
)
182 for (i
= 0; i
< 64; i
++)
185 avic
[VECTOR
+ i
] = (unsigned long)UIE_VECTOR
;
190 avic
[INTDISNUM
] = ints
;
191 avic
[VECTOR
+ ints
] = (unsigned long)UIE_VECTOR
;
195 static void set_int_type(int i
, enum INT_TYPE intstype
)
197 /* INTTYPEH: vectors 63-32, INTTYPEL: vectors 31-0 */
198 volatile unsigned long * const reg
= &avic
[INTTYPE
+ 1 - (i
>> 5)];
199 unsigned long val
= 1L << (i
& 0x1f);
201 if (intstype
== INT_TYPE_IRQ
)
209 void avic_set_int_type(enum IMX31_INT_LIST ints
, enum INT_TYPE intstype
)
211 int oldstatus
= disable_interrupt_save(IRQ_FIQ_STATUS
);
216 for (i
= 0; i
< 64; i
++)
217 set_int_type(i
, intstype
);
221 set_int_type(ints
, intstype
);
224 restore_interrupt(oldstatus
);
227 void avic_set_ni_level(int level
)
230 level
= 0x1f; /* -1 */
234 avic
[NIMASK
] = level
;