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 static const char * avic_int_names
[64] =
30 "RESERVED0", "RESERVED1", "RESERVED2", "I2C3",
31 "I2C2", "MPEG4_ENCODER", "RTIC", "FIR",
32 "MMC/SDHC2", "MMC/SDHC1", "I2C1", "SSI2",
33 "SSI1", "CSPI2", "CSPI1", "ATA",
34 "MBX", "CSPI3", "UART3", "IIM",
35 "SIM1", "SIM2", "RNGA", "EVTMON",
36 "KPP", "RTC", "PWN", "EPIT2",
37 "EPIT1", "GPT", "PWR_FAIL", "CCM_DVFS",
38 "UART2", "NANDFC", "SDMA", "USB_HOST1",
39 "USB_HOST2", "USB_OTG", "RESERVED3", "MSHC1",
40 "MSHC2", "IPU_ERR", "IPU", "RESERVED4",
41 "RESERVED5", "UART1", "UART4", "UART5",
42 "ETC_IRQ", "SCC_SCM", "SCC_SMN", "GPIO2",
43 "GPIO1", "CCM_CLK", "PCMCIA", "WDOG",
44 "GPIO3", "RESERVED6", "EXT_PWMG", "EXT_TEMP",
45 "EXT_SENS1", "EXT_SENS2", "EXT_WDOG", "EXT_TV"
54 "mrs %0, cpsr \n" /* Mask core IRQ/FIQ */
55 "orr %0, %0, #0xc0 \n"
57 "and %0, %0, #0x1f \n" /* Get mode bits */
61 offset
= mode
== 0x11 ?
62 (int32_t)AVIC_FIVECSR
: ((int32_t)AVIC_NIVECSR
>> 16);
64 panicf("Unhandled %s %d: %s",
65 mode
== 0x11 ? "FIQ" : "IRQ", offset
,
66 offset
>= 0 ? avic_int_names
[offset
] : "<Unknown>");
71 void __attribute__((interrupt("IRQ"))) irq_handler(void)
73 const int offset
= (int32_t)AVIC_NIVECSR
>> 16;
77 /* This is called occasionally for some unknown reason even with the
78 * avic enabled but returning normally appears to cause no harm. The
79 * KPP and ATA seem to have a part in it (common but multiplexed pins
80 * that can interfere). It will be investigated more thoroughly but
81 * for now it is simply an occasional irritant. */
85 disable_interrupt(IRQ_FIQ_STATUS
);
86 panicf("Unhandled IRQ %d in irq_handler: %s", offset
,
87 offset
>= 0 ? avic_int_names
[offset
] : "<Unknown>");
91 /* Accoring to section 9.3.5 of the UM, the AVIC doesn't accelerate
92 * fast interrupts and they must be dispatched */
93 void __attribute__((naked
)) fiq_handler(void)
96 "mov r10, #0x68000000 \n" /* load AVIC base address */
97 "ldr r9, [r10, #0x44] \n" /* read FIVECSR of AVIC */
98 "add r10, r10, #0x100 \n" /* move pointer to base of VECTOR table */
99 "ldr r8, [r10, r9, lsl #2] \n" /* read FIQ vector from VECTOR table */
100 "bx r8 \n" /* jump to FIQ service routine */
106 struct avic_map
* const avic
= (struct avic_map
*)AVIC_BASE_ADDR
;
109 /* Disable all interrupts and set to unhandled */
110 avic_disable_int(INT_ALL
);
112 /* Reset AVIC control */
115 /* Init all interrupts to type IRQ */
116 avic_set_int_type(INT_ALL
, INT_TYPE_IRQ
);
118 /* Set all normal to lowest priority */
119 for (i
= 0; i
< 8; i
++)
120 avic
->nipriority
[i
] = 0;
122 /* Set NM bit to enable VIC */
123 avic
->intcntl
|= AVIC_INTCNTL_NM
;
125 /* Enable VE bit in CP15 Control reg to enable VIC */
127 "mrc p15, 0, r0, c1, c0, 0 \n"
128 "orr r0, r0, #(1 << 24) \n"
129 "mcr p15, 0, r0, c1, c0, 0 \n"
132 /* Enable normal interrupts at all priorities */
133 avic
->nimask
= AVIC_NIL_ENABLE
;
136 void avic_set_int_priority(enum IMX31_INT_LIST ints
,
137 unsigned long ni_priority
)
139 struct avic_map
* const avic
= (struct avic_map
*)AVIC_BASE_ADDR
;
140 volatile uint32_t *reg
= &avic
->nipriority
[7 - (ints
>> 3)];
141 unsigned int shift
= (ints
& 0x7) << 2;
142 uint32_t mask
= 0xful
<< shift
;
143 *reg
= (*reg
& ~mask
) | ((ni_priority
<< shift
) & mask
);
146 void avic_enable_int(enum IMX31_INT_LIST ints
, enum INT_TYPE intstype
,
147 unsigned long ni_priority
, void (*handler
)(void))
149 struct avic_map
* const avic
= (struct avic_map
*)AVIC_BASE_ADDR
;
150 int oldstatus
= disable_interrupt_save(IRQ_FIQ_STATUS
);
152 if (ints
!= INT_ALL
) /* No mass-enable allowed */
154 avic_set_int_type(ints
, intstype
);
155 avic
->vector
[ints
] = (long)handler
;
156 avic
->intennum
= ints
;
157 avic_set_int_priority(ints
, ni_priority
);
160 restore_interrupt(oldstatus
);
163 void avic_disable_int(enum IMX31_INT_LIST ints
)
165 struct avic_map
* const avic
= (struct avic_map
*)AVIC_BASE_ADDR
;
170 for (i
= 0; i
< 64; i
++)
173 avic
->vector
[i
] = (long)UIE_VECTOR
;
178 avic
->intdisnum
= ints
;
179 avic
->vector
[ints
] = (long)UIE_VECTOR
;
183 static void set_int_type(int i
, enum INT_TYPE intstype
)
185 /* INTTYPEH: vectors 63-32, INTTYPEL: vectors 31-0 */
186 struct avic_map
* const avic
= (struct avic_map
*)AVIC_BASE_ADDR
;
187 volatile uint32_t *reg
= &avic
->inttype
[1 - (i
>> 5)];
188 uint32_t val
= 1L << (i
& 0x1f);
190 if (intstype
== INT_TYPE_IRQ
)
198 void avic_set_int_type(enum IMX31_INT_LIST ints
, enum INT_TYPE intstype
)
200 int oldstatus
= disable_interrupt_save(IRQ_FIQ_STATUS
);
205 for (i
= 0; i
< 64; i
++)
206 set_int_type(i
, intstype
);
210 set_int_type(ints
, intstype
);
213 restore_interrupt(oldstatus
);
216 void avic_set_ni_level(unsigned int level
)
218 AVIC_NIMASK
= level
> 0x1f ? 0x1f : level
;