Gigabeat S: Those odd calls to irq_handler can still happen rarely after executing...
[kugel-rb.git] / firmware / target / arm / imx31 / avic-imx31.c
blob51ba14d0b3e0b8ec4d8bb48f4d530ea255718e89
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include <stdio.h>
22 #include "system.h"
23 #include "imx31l.h"
24 #include "avic-imx31.h"
25 #include "panic.h"
26 #include "debug.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"
48 void UIE_VECTOR(void)
50 int mode;
51 int offset;
53 asm volatile (
54 "mrs %0, cpsr \n" /* Mask core IRQ/FIQ */
55 "orr %0, %0, #0xc0 \n"
56 "msr cpsr_c, %0 \n"
57 "and %0, %0, #0x1f \n" /* Get mode bits */
58 : "=&r"(mode)
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>");
69 #if 0
70 /* We use the AVIC */
71 void __attribute__((interrupt("IRQ"))) irq_handler(void)
73 const int offset = (int32_t)AVIC_NIVECSR >> 16;
75 if (offset == -1)
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. */
82 return;
85 disable_interrupt(IRQ_FIQ_STATUS);
86 panicf("Unhandled IRQ %d in irq_handler: %s", offset,
87 offset >= 0 ? avic_int_names[offset] : "<Unknown>");
89 #endif /* 0 */
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)
95 asm volatile (
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 */
104 void avic_init(void)
106 struct avic_map * const avic = (struct avic_map *)AVIC_BASE_ADDR;
107 int i;
109 /* Disable all interrupts and set to unhandled */
110 avic_disable_int(INT_ALL);
112 /* Reset AVIC control */
113 avic->intcntl = 0;
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 */
126 asm volatile (
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"
130 : : : "r0");
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;
166 uint32_t i;
168 if (ints == INT_ALL)
170 for (i = 0; i < 64; i++)
172 avic->intdisnum = i;
173 avic->vector[i] = (long)UIE_VECTOR;
176 else
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)
191 val = *reg & ~val;
192 else
193 val = *reg | val;
195 *reg = val;
198 void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype)
200 int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
202 if (ints == INT_ALL)
204 int i;
205 for (i = 0; i < 64; i++)
206 set_int_type(i, intstype);
208 else
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;