diff options
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/avic-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/avic-imx31.c | 305 |
1 files changed, 131 insertions, 174 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c b/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c index 8236a38014..99a52e56d5 100644 --- a/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c | |||
@@ -20,204 +20,161 @@ | |||
20 | #include "system.h" | 20 | #include "system.h" |
21 | #include "imx31l.h" | 21 | #include "imx31l.h" |
22 | #include "avic-imx31.h" | 22 | #include "avic-imx31.h" |
23 | #include "panic.h" | ||
23 | #include "debug.h" | 24 | #include "debug.h" |
24 | 25 | ||
26 | static const char * avic_int_names[64] = | ||
27 | { | ||
28 | "RESERVED0", "RESERVED1", "RESERVED2", "I2C3", | ||
29 | "I2C2", "MPEG4_ENCODER", "RTIC", "FIR", | ||
30 | "MMC/SDHC2", "MMC/SDHC1", "I2C1", "SSI2", | ||
31 | "SSI1", "CSPI2", "CSPI1", "ATA", | ||
32 | "MBX", "CSPI3", "UART3", "IIM", | ||
33 | "SIM1", "SIM2", "RNGA", "EVTMON", | ||
34 | "KPP", "RTC", "PWN", "EPIT2", | ||
35 | "EPIT1", "GPT", "PWR_FAIL", "CCM_DVFS", | ||
36 | "UART2", "NANDFC", "SDMA", "USB_HOST1", | ||
37 | "USB_HOST2", "USB_OTG", "RESERVED3", "MSHC1", | ||
38 | "MSHC2", "IPU_ERR", "IPU", "RESERVED4", | ||
39 | "RESERVED5", "UART1", "UART4", "UART5", | ||
40 | "ETC_IRQ", "SCC_SCM", "SCC_SMN", "GPIO2", | ||
41 | "GPIO1", "CCM_CLK", "PCMCIA", "WDOG", | ||
42 | "GPIO3", "RESERVED6", "EXT_PWMG", "EXT_TEMP", | ||
43 | "EXT_SENS1", "EXT_SENS2", "EXT_WDOG", "EXT_TV" | ||
44 | }; | ||
45 | |||
46 | static void UIE_VECTOR(void) | ||
47 | { | ||
48 | set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); | ||
49 | long offset = FIVECSR; | ||
50 | long offsetn = (long)NIVECSR >> 16; | ||
51 | |||
52 | if (offsetn == -1) | ||
53 | offset = offsetn; /* Could be FIQ */ | ||
54 | |||
55 | panicf("Unhandled %s %ld: %s", | ||
56 | offsetn >= 0 ? "IRQ" : "FIQ", offset, | ||
57 | offset >= 0 ? avic_int_names[offset] : ""); | ||
58 | } | ||
59 | |||
60 | /* We use the AVIC */ | ||
61 | void __attribute__((naked)) irq_handler(void) | ||
62 | { | ||
63 | panicf("Unhandled IRQ"); | ||
64 | } | ||
65 | |||
66 | /* Accoring to section 9.3.5 of the UM, the AVIC doesn't accelerate | ||
67 | * fast interrupts and they must be dispatched */ | ||
68 | void __attribute__((naked)) fiq_handler(void) | ||
69 | { | ||
70 | asm volatile ( | ||
71 | "mov r10, #0x6c000000 \n" /* load AVIC base address */ | ||
72 | "ldr r9, [r10, #0x44] \n" /* read FIVECSR of AVIC */ | ||
73 | "add r10, r10, #100 \n" /* move pointer to base of VECTOR table */ | ||
74 | "ldr r8, [r10, r9, lsl #2] \n" /* read FIQ vector from VECTOR table */ | ||
75 | "bx r8 \n" /* jump to FIQ service routine */ | ||
76 | ); | ||
77 | } | ||
78 | |||
25 | void avic_init(void) | 79 | void avic_init(void) |
26 | { | 80 | { |
27 | /*following the steps in the AVIC setup in imx31 man*/ | 81 | /* Disable all interrupts and set to unhandled */ |
82 | avic_disable_int(ALL); | ||
28 | 83 | ||
29 | /*Initialize interrupt structures*/ | 84 | /* Init all interrupts to type IRQ */ |
30 | int i,avicstart; | 85 | avic_set_int_type(ALL, IRQ); |
31 | /*get start of avic_init section for address calculation*/ | ||
32 | __asm__ ("ldr %0,=_avicstart\n\t" | ||
33 | :"=r"(avicstart):); | ||
34 | 86 | ||
35 | for(i=0; i < 64;i++) | 87 | /* Set NM bit to enable VIC */ |
36 | { | 88 | INTCNTL |= INTCNTL_NM; |
37 | imx31_int[i].name = (char *)&imx31_int_names[i]; | ||
38 | imx31_int[i].int_type=IRQ; | ||
39 | /*integer i MUST be multiplied by 8 b/c gnu as | ||
40 | generates 2 instructions for each vector instruction | ||
41 | in vector_init(). Hence the value of 8 byte intervals | ||
42 | between each vector start address*/ | ||
43 | imx31_int[i].addr=(avicstart+(i*8)); | ||
44 | imx31_int[i].priority=0; | ||
45 | imx31_int[i].pInt_Handler=Unhandled_Int; | ||
46 | } | ||
47 | |||
48 | /*enable all Interrupts*/ | ||
49 | avic_enable_int(ALL,IRQ,0); | ||
50 | |||
51 | /*Setup all interrupt type IRQ*/ | ||
52 | avic_set_int_type(ALL,IRQ); | ||
53 | |||
54 | /*Set NM bit to enable VIC*/ | ||
55 | INTCNTL |= (1 << 18); | ||
56 | 89 | ||
57 | /*Setup Registers Vector0-Vector63 for interrupt handler functions*/ | 90 | /* Enable IRQ/FIQ in imx31 INTCNTL reg */ |
58 | for(i=0; i < 64;i++) | 91 | INTCNTL &= ~(INTCNTL_ABFEN | INTCNTL_NIDIS | INTCNTL_FIDIS); |
59 | writel(imx31_int[i].addr,(VECTOR_BASE_ADDR+(i*8))); | 92 | |
60 | 93 | /* Enable VE bit in CP15 Control reg to enable VIC */ | |
61 | /*disable FIQ for now until the interrupt handlers are more mature...*/ | 94 | asm volatile ( |
62 | disable_fiq(); | 95 | "mrc p15, 0, r0, c1, c0, 0 \n" |
63 | /*enable_fiq();*/ | 96 | "orr r0, r0, #(1 << 24) \n" |
64 | 97 | "mcr p15, 0, r0, c1, c0, 0 \n" | |
65 | /*enable IRQ in imx31 INTCNTL reg*/ | 98 | : : : "r0"); |
66 | INTCNTL &= ~(NIDIS); | 99 | |
67 | /*disable FIQ in imx31 INTCNTL reg*/ | 100 | /* Enable normal interrupts at all priorities */ |
68 | INTCNTL |= FIDIS; | 101 | NIMASK = 16; |
69 | |||
70 | /*enable IRQ in ARM11 core, enable VE bit in CP15 Control reg to enable VIC*/ | ||
71 | __asm__ ("mrs r0,cpsr\t\n" | ||
72 | "bic r0,r0,#0x80\t\n" | ||
73 | "msr cpsr,r0\t\n" | ||
74 | "mrc p15,0,r0,c1,c0,0\n\t" | ||
75 | "orr r0,r0,#0x1000000\n\t" | ||
76 | "mcr p15,0,r0,c1,c0,0\n\t"::: | ||
77 | "r0"); | ||
78 | } | 102 | } |
79 | 103 | ||
80 | void avic_enable_int(enum IMX31_INT_LIST ints, enum INT_TYPE intstype, | 104 | void avic_enable_int(enum IMX31_INT_LIST ints, enum INT_TYPE intstype, |
81 | void (*pInt_Handler) (void)) | 105 | void (*handler)(void)) |
82 | { | 106 | { |
83 | int i; | 107 | int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, |
108 | IRQ_FIQ_STATUS); | ||
84 | 109 | ||
85 | if(ints == ALL) | 110 | if (ints != ALL) /* No mass-enable allowed */ |
86 | { | 111 | { |
87 | avic_set_int_type(ALL,intstype); | 112 | avic_set_int_type(ints, intstype); |
88 | for(i=0;i<64;i++) | 113 | VECTOR(ints) = (long)handler; |
89 | INTENNUM= (long)i; | 114 | INTENNUM = ints; |
90 | if(!(*pInt_Handler)) | 115 | } |
91 | pInt_Handler=Unhandled_Int; | 116 | |
92 | return; | 117 | set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); |
93 | } | ||
94 | |||
95 | imx31_int[ints].int_type=intstype; | ||
96 | imx31_int[ints].pInt_Handler=pInt_Handler; | ||
97 | avic_set_int_type(ints,intstype); | ||
98 | INTENNUM=(long)ints; | ||
99 | } | 118 | } |
100 | 119 | ||
101 | void avic_disable_int(enum IMX31_INT_LIST ints) | 120 | void avic_disable_int(enum IMX31_INT_LIST ints) |
102 | { | 121 | { |
103 | int i; | 122 | long i; |
104 | 123 | ||
105 | if(ints == ALL) | 124 | if (ints == ALL) |
106 | { | 125 | { |
107 | for(i=0;i<64;i++) | 126 | for (i = 0; i < 64; i++) |
108 | INTDISNUM=(long)i; | 127 | { |
109 | imx31_int[ints].pInt_Handler=Unhandled_Int; | 128 | INTDISNUM = i; |
110 | return; | 129 | VECTOR(i) = (long)UIE_VECTOR; |
130 | } | ||
111 | } | 131 | } |
112 | 132 | else | |
113 | INTDISNUM=(long)ints; | 133 | { |
134 | INTDISNUM = ints; | ||
135 | VECTOR(ints) = (long)UIE_VECTOR; | ||
136 | } | ||
114 | } | 137 | } |
115 | 138 | ||
116 | void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype) | 139 | static void set_int_type(int i, enum INT_TYPE intstype) |
117 | { | 140 | { |
118 | int i; | 141 | volatile unsigned long *reg; |
119 | if(ints == ALL) | 142 | long val; |
120 | { | ||
121 | imx31_int[ints].int_type=intstype; | ||
122 | for(i=0;i<64;i++) | ||
123 | { | ||
124 | if(intstype > CCM_DVFS) | ||
125 | INTTYPEH=(long)(intstype-32); | ||
126 | else INTTYPEL=(long)intstype; | ||
127 | } | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | imx31_int[ints].int_type=intstype; | ||
132 | if(intstype > CCM_DVFS) | ||
133 | INTTYPEH=(long)(intstype-32); | ||
134 | else INTTYPEL=(long)intstype; | ||
135 | } | ||
136 | 143 | ||
137 | void Unhandled_Int(void) | 144 | if (i >= 32) |
138 | { | 145 | { |
139 | enum IMX31_INT_LIST ints = 0; | 146 | reg = &INTTYPEH; |
140 | DEBUGF("Unhandled Interrupt:\n"); | 147 | val = 1L << (i - 32); |
141 | DEBUGF("Name : %s\n",imx31_int[ints].name); | 148 | } |
142 | DEBUGF("Interrupt Type : "); | 149 | else |
143 | if(imx31_int[ints].int_type==IRQ) | 150 | { |
144 | DEBUGF("IRQ\n"); | 151 | reg = &INTTYPEL; |
145 | else DEBUGF("FIQ\n"); | 152 | val = 1L << i; |
146 | DEBUGF("Handler Address : 0x%x\n",imx31_int[ints].addr); | 153 | } |
147 | DEBUGF("Priority : %d",imx31_int[ints].priority); | 154 | |
155 | if (intstype == IRQ) | ||
156 | val = *reg & ~val; | ||
157 | else | ||
158 | val = *reg | val; | ||
159 | |||
160 | *reg = val; | ||
148 | } | 161 | } |
149 | 162 | ||
150 | void vector_init(void) | 163 | void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype) |
151 | { | 164 | { |
152 | 165 | int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, | |
153 | /*64 branch instructions, one for every vector in avic | 166 | IRQ_FIQ_STATUS); |
154 | A better idea would to calculate the shellcode for each of these | 167 | |
155 | instructions...*/ | 168 | if (ints == ALL) |
156 | 169 | { | |
157 | 170 | int i; | |
158 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED0].pInt_Handler)); | 171 | for (i = 0; i < 64; i++) |
159 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED1].pInt_Handler)); | 172 | set_int_type(i, intstype); |
160 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED2].pInt_Handler)); | 173 | } |
161 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[I2C3].pInt_Handler)); | 174 | else |
162 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[I2C2].pInt_Handler)); | 175 | { |
163 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MPEG4_ENCODER].pInt_Handler)); | 176 | set_int_type(ints, intstype); |
164 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RTIC].pInt_Handler)); | 177 | } |
165 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[FIR].pInt_Handler)); | 178 | |
166 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MMC_SDHC2].pInt_Handler)); | 179 | set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); |
167 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MMC_SDHC1].pInt_Handler)); | ||
168 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[I2C1].pInt_Handler)); | ||
169 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SSI2].pInt_Handler)); | ||
170 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SSI1].pInt_Handler)); | ||
171 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[CSPI2].pInt_Handler)); | ||
172 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[CSPI1].pInt_Handler)); | ||
173 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[ATA].pInt_Handler)); | ||
174 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MBX].pInt_Handler)); | ||
175 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[CSPI3].pInt_Handler)); | ||
176 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[UART3].pInt_Handler)); | ||
177 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[IIM].pInt_Handler)); | ||
178 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SIM1].pInt_Handler)); | ||
179 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SIM2].pInt_Handler)); | ||
180 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RNGA].pInt_Handler)); | ||
181 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EVTMON].pInt_Handler)); | ||
182 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[KPP].pInt_Handler)); | ||
183 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RTC].pInt_Handler)); | ||
184 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[PWN].pInt_Handler)); | ||
185 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EPIT2].pInt_Handler)); | ||
186 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EPIT1].pInt_Handler)); | ||
187 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[GPT].pInt_Handler)); | ||
188 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[PWR_FAIL].pInt_Handler)); | ||
189 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[CCM_DVFS].pInt_Handler)); | ||
190 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[UART2].pInt_Handler)); | ||
191 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[NANDFC].pInt_Handler)); | ||
192 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SDMA].pInt_Handler)); | ||
193 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[USB_HOST1].pInt_Handler)); | ||
194 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[USB_HOST2].pInt_Handler)); | ||
195 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[USB_OTG].pInt_Handler)); | ||
196 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED3].pInt_Handler)); | ||
197 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MSHC1].pInt_Handler)); | ||
198 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[MSHC2].pInt_Handler)); | ||
199 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[IPU_ERR].pInt_Handler)); | ||
200 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[IPU].pInt_Handler)); | ||
201 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED4].pInt_Handler)); | ||
202 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED5].pInt_Handler)); | ||
203 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[UART1].pInt_Handler)); | ||
204 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[UART4].pInt_Handler)); | ||
205 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[UART5].pInt_Handler)); | ||
206 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[ETC_IRQ].pInt_Handler)); | ||
207 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SCC_SCM].pInt_Handler)); | ||
208 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[SCC_SMN].pInt_Handler)); | ||
209 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[GPIO2].pInt_Handler)); | ||
210 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[GPIO1].pInt_Handler)); | ||
211 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[CCM_CLK].pInt_Handler)); | ||
212 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[PCMCIA].pInt_Handler)); | ||
213 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[WDOG].pInt_Handler)); | ||
214 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[GPIO3].pInt_Handler)); | ||
215 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[RESERVED6].pInt_Handler)); | ||
216 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_PWMG].pInt_Handler)); | ||
217 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_TEMP].pInt_Handler)); | ||
218 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_SENS1].pInt_Handler)); | ||
219 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_SENS2].pInt_Handler)); | ||
220 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_WDOG].pInt_Handler)); | ||
221 | __asm__("ldr pc, %0\n\t"::"g"(imx31_int[EXT_TV].pInt_Handler)); | ||
222 | |||
223 | } | 180 | } |