]>
Commit | Line | Data |
---|---|---|
0db5bca8 WD |
1 | /* |
2 | * (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
3 | * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
0db5bca8 WD |
6 | */ |
7 | ||
8 | /* | |
9 | * File: interrupt.c | |
8bde7f77 | 10 | * |
0db5bca8 WD |
11 | * Discription: Contains interrupt routines needed by U-Boot |
12 | * | |
13 | */ | |
14 | ||
15 | #include <common.h> | |
b6e4c403 | 16 | #include <command.h> |
0db5bca8 WD |
17 | #include <mpc5xx.h> |
18 | #include <asm/processor.h> | |
19 | ||
b6e4c403 WD |
20 | #if defined(CONFIG_PATI) |
21 | /* PATI uses IRQs for PCI doorbell */ | |
22 | #undef NR_IRQS | |
23 | #define NR_IRQS 16 | |
24 | #endif | |
25 | ||
0db5bca8 WD |
26 | struct interrupt_action { |
27 | interrupt_handler_t *handler; | |
28 | void *arg; | |
b6e4c403 | 29 | int count; |
0db5bca8 WD |
30 | }; |
31 | ||
32 | static struct interrupt_action irq_vecs[NR_IRQS]; | |
33 | ||
0db5bca8 | 34 | /* |
8bde7f77 | 35 | * Initialise interrupts |
0db5bca8 WD |
36 | */ |
37 | ||
a8c7c708 | 38 | int interrupt_init_cpu (ulong *decrementer_count) |
0db5bca8 | 39 | { |
6d0f6bcf | 40 | volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; |
b6e4c403 | 41 | int vec; |
0db5bca8 WD |
42 | |
43 | /* Decrementer used here for status led */ | |
6d0f6bcf | 44 | *decrementer_count = get_tbclk () / CONFIG_SYS_HZ; |
0db5bca8 WD |
45 | |
46 | /* Disable all interrupts */ | |
47 | immr->im_siu_conf.sc_simask = 0; | |
b6e4c403 WD |
48 | for (vec=0; vec<NR_IRQS; vec++) { |
49 | irq_vecs[vec].handler = NULL; | |
50 | irq_vecs[vec].arg = NULL; | |
51 | irq_vecs[vec].count = 0; | |
52 | } | |
0db5bca8 | 53 | |
0db5bca8 WD |
54 | return (0); |
55 | } | |
56 | ||
57 | /* | |
58 | * Handle external interrupts | |
59 | */ | |
60 | void external_interrupt (struct pt_regs *regs) | |
61 | { | |
6d0f6bcf | 62 | volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; |
0db5bca8 WD |
63 | int irq; |
64 | ulong simask, newmask; | |
65 | ulong vec, v_bit; | |
66 | ||
67 | /* | |
68 | * read the SIVEC register and shift the bits down | |
69 | * to get the irq number | |
70 | */ | |
71 | vec = immr->im_siu_conf.sc_sivec; | |
72 | irq = vec >> 26; | |
73 | v_bit = 0x80000000UL >> irq; | |
74 | ||
75 | /* | |
76 | * Read Interrupt Mask Register and Mask Interrupts | |
77 | */ | |
78 | simask = immr->im_siu_conf.sc_simask; | |
79 | newmask = simask & (~(0xFFFF0000 >> irq)); | |
80 | immr->im_siu_conf.sc_simask = newmask; | |
81 | ||
82 | if (!(irq & 0x1)) { /* External Interrupt ? */ | |
83 | ulong siel; | |
84 | ||
85 | /* | |
86 | * Read Interrupt Edge/Level Register | |
87 | */ | |
88 | siel = immr->im_siu_conf.sc_siel; | |
89 | ||
90 | if (siel & v_bit) { /* edge triggered interrupt ? */ | |
91 | /* | |
92 | * Rewrite SIPEND Register to clear interrupt | |
93 | */ | |
94 | immr->im_siu_conf.sc_sipend = v_bit; | |
95 | } | |
96 | } | |
97 | ||
98 | if (irq_vecs[irq].handler != NULL) { | |
99 | irq_vecs[irq].handler (irq_vecs[irq].arg); | |
100 | } else { | |
101 | printf ("\nBogus External Interrupt IRQ %d Vector %ld\n", | |
102 | irq, vec); | |
103 | /* turn off the bogus interrupt to avoid it from now */ | |
104 | simask &= ~v_bit; | |
105 | } | |
106 | /* | |
107 | * Re-Enable old Interrupt Mask | |
108 | */ | |
109 | immr->im_siu_conf.sc_simask = simask; | |
110 | } | |
111 | ||
112 | /* | |
113 | * Install and free an interrupt handler | |
114 | */ | |
115 | void irq_install_handler (int vec, interrupt_handler_t * handler, | |
116 | void *arg) | |
117 | { | |
6d0f6bcf | 118 | volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; |
0db5bca8 WD |
119 | /* SIU interrupt */ |
120 | if (irq_vecs[vec].handler != NULL) { | |
121 | printf ("SIU interrupt %d 0x%x\n", | |
122 | vec, | |
123 | (uint) handler); | |
124 | } | |
125 | irq_vecs[vec].handler = handler; | |
126 | irq_vecs[vec].arg = arg; | |
127 | immr->im_siu_conf.sc_simask |= 1 << (31 - vec); | |
128 | #if 0 | |
129 | printf ("Install SIU interrupt for vector %d ==> %p\n", | |
130 | vec, handler); | |
131 | #endif | |
132 | } | |
133 | ||
134 | void irq_free_handler (int vec) | |
135 | { | |
6d0f6bcf | 136 | volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; |
0db5bca8 WD |
137 | /* SIU interrupt */ |
138 | #if 0 | |
139 | printf ("Free CPM interrupt for vector %d\n", | |
140 | vec); | |
141 | #endif | |
142 | immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec)); | |
143 | irq_vecs[vec].handler = NULL; | |
144 | irq_vecs[vec].arg = NULL; | |
145 | } | |
146 | ||
0db5bca8 | 147 | /* |
8bde7f77 | 148 | * Timer interrupt - gets called when bit 0 of DEC changes from |
0db5bca8 WD |
149 | * 0. Decrementer is enabled with bit TBE in TBSCR. |
150 | */ | |
a8c7c708 | 151 | void timer_interrupt_cpu (struct pt_regs *regs) |
0db5bca8 | 152 | { |
6d0f6bcf | 153 | volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; |
0db5bca8 | 154 | |
0db5bca8 WD |
155 | #if 0 |
156 | printf ("*** Timer Interrupt *** "); | |
157 | #endif | |
158 | /* Reset Timer Status Bit and Timers Interrupt Status */ | |
159 | immr->im_clkrstk.cark_plprcrk = KAPWR_KEY; | |
160 | __asm__ ("nop"); | |
161 | immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST; | |
8bde7f77 | 162 | |
a8c7c708 | 163 | return; |
0db5bca8 | 164 | } |
b6e4c403 | 165 | |
4431283c | 166 | #if defined(CONFIG_CMD_IRQ) |
b6e4c403 WD |
167 | /******************************************************************************* |
168 | * | |
169 | * irqinfo - print information about IRQs | |
170 | * | |
171 | */ | |
54841ab5 | 172 | int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
b6e4c403 WD |
173 | { |
174 | int vec; | |
175 | ||
176 | printf ("\nInterrupt-Information:\n"); | |
177 | printf ("Nr Routine Arg Count\n"); | |
178 | ||
179 | for (vec=0; vec<NR_IRQS; vec++) { | |
180 | if (irq_vecs[vec].handler != NULL) { | |
181 | printf ("%02d %08lx %08lx %d\n", | |
182 | vec, | |
183 | (ulong)irq_vecs[vec].handler, | |
184 | (ulong)irq_vecs[vec].arg, | |
185 | irq_vecs[vec].count); | |
186 | } | |
187 | } | |
188 | return 0; | |
189 | } | |
190 | ||
191 | ||
4431283c | 192 | #endif |