i.MX31: Make some style changes to some driver code so that hardware vs. variable...
[kugel-rb.git] / firmware / target / arm / imx31 / avic-imx31.c
blob5bf7275e07e05698eb06838d05c26712128710fb
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 #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"
64 void UIE_VECTOR(void)
66 unsigned long mode;
67 int offset;
69 asm volatile (
70 "mrs %0, cpsr \n" /* Mask core IRQ/FIQ */
71 "orr %0, %0, #0xc0 \n"
72 "msr cpsr_c, %0 \n"
73 "and %0, %0, #0x1f \n" /* Get mode bits */
74 : "=&r"(mode)
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>");
84 #if 0
85 /* We use the AVIC */
86 void __attribute__((interrupt("IRQ"))) irq_handler(void)
88 int offset = (long)avic[NIVECSR] >> 16;
90 if (offset == -1)
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. */
97 return;
100 disable_interrupt(IRQ_FIQ_STATUS);
101 panicf("Unhandled IRQ %d in irq_handler: %s", offset,
102 offset >= 0 ? avic_int_names[offset] : "<Unknown>");
104 #endif /* 0 */
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)
110 asm volatile (
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 */
119 void avic_init(void)
121 int i;
123 /* Disable all interrupts and set to unhandled */
124 avic_disable_int(INT_ALL);
126 /* Reset AVIC control */
127 avic[INTCNTL] = 0;
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 |
139 AVIC_INTCNTL_NIAD;
141 /* Enable VE bit in CP15 Control reg to enable VIC */
142 asm volatile (
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"
146 : : : "r0");
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)
179 if (ints == INT_ALL)
181 int i;
182 for (i = 0; i < 64; i++)
184 avic[INTDISNUM] = i;
185 avic[VECTOR + i] = (unsigned long)UIE_VECTOR;
188 else
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)
202 val = *reg & ~val;
203 else
204 val = *reg | val;
206 *reg = val;
209 void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype)
211 int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
213 if (ints == INT_ALL)
215 int i;
216 for (i = 0; i < 64; i++)
217 set_int_type(i, intstype);
219 else
221 set_int_type(ints, intstype);
224 restore_interrupt(oldstatus);
227 void avic_set_ni_level(int level)
229 if (level < 0)
230 level = 0x1f; /* -1 */
231 else if (level > 15)
232 level = 15;
234 avic[NIMASK] = level;