ColdFire: Multiple fixes for MCF5445x platforms
[platform/kernel/u-boot.git] / lib_m68k / interrupts.c
1 /*
2  * (C) Copyright 2000-2004
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2007 Freescale Semiconductor Inc
6  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <watchdog.h>
29 #include <asm/processor.h>
30 #include <asm/immap.h>
31
32 #define NR_IRQS         (CFG_NUM_IRQS)
33
34 /*
35  * Interrupt vector functions.
36  */
37 struct interrupt_action {
38         interrupt_handler_t *handler;
39         void *arg;
40 };
41
42 static struct interrupt_action irq_vecs[NR_IRQS];
43
44 static __inline__ unsigned short get_sr (void)
45 {
46         unsigned short sr;
47
48         asm volatile ("move.w %%sr,%0":"=r" (sr):);
49
50         return sr;
51 }
52
53 static __inline__ void set_sr (unsigned short sr)
54 {
55         asm volatile ("move.w %0,%%sr"::"r" (sr));
56 }
57
58 /************************************************************************/
59 /*
60  * Install and free an interrupt handler
61  */
62 void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
63 {
64         if ((vec < 0) || (vec > NR_IRQS)) {
65                 printf ("irq_install_handler: wrong interrupt vector %d\n",
66                         vec);
67                 return;
68         }
69
70         irq_vecs[vec].handler = handler;
71         irq_vecs[vec].arg = arg;
72 }
73
74 void irq_free_handler (int vec)
75 {
76         if ((vec < 0) || (vec > NR_IRQS)) {
77                 return;
78         }
79
80         irq_vecs[vec].handler = NULL;
81         irq_vecs[vec].arg = NULL;
82 }
83
84 void enable_interrupts (void)
85 {
86         unsigned short sr;
87
88         sr = get_sr ();
89         set_sr (sr & ~0x0700);
90 }
91
92 int disable_interrupts (void)
93 {
94         unsigned short sr;
95
96         sr = get_sr ();
97         set_sr (sr | 0x0700);
98
99         return ((sr & 0x0700) == 0);    /* return TRUE, if interrupts were enabled before */
100 }
101
102 void int_handler (struct pt_regs *fp)
103 {
104         int vec;
105
106         vec = (fp->vector >> 2) & 0xff;
107         if (vec > 0x40)
108                 vec -= 0x40;
109
110         if (irq_vecs[vec].handler != NULL) {
111                 irq_vecs[vec].handler (irq_vecs[vec].arg);
112         } else {
113                 printf ("\nBogus External Interrupt Vector %d\n", vec);
114         }
115 }