45997d6eae0640dee7e36cffdcf1460afd336379
[platform/kernel/u-boot.git] / arch / powerpc / cpu / ppc4xx / interrupts.c
1 /*
2  * (C) Copyright 2000-2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2002 (440 port)
6  * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
7  *
8  * (C) Copyright 2003 (440GX port)
9  * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
10  *
11  * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
12  * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@gmail.com
13  * Work supported by Qtechnology (htpp://qtec.com)
14  *
15  * SPDX-License-Identifier:     GPL-2.0+
16  */
17
18 #include <common.h>
19 #include <watchdog.h>
20 #include <command.h>
21 #include <asm/processor.h>
22 #include <asm/interrupt.h>
23 #include <asm/ppc4xx.h>
24 #include <ppc_asm.tmpl>
25 #include <commproc.h>
26
27 DECLARE_GLOBAL_DATA_PTR;
28
29 /*
30  * CPM interrupt vector functions.
31  */
32 struct  irq_action {
33         interrupt_handler_t *handler;
34         void *arg;
35         int count;
36 };
37 static struct irq_action irq_vecs[IRQ_MAX];
38
39 #if defined(CONFIG_440)
40
41 /* SPRN changed in 440 */
42 static __inline__ void set_evpr(unsigned long val)
43 {
44         asm volatile("mtspr 0x03f,%0" : : "r" (val));
45 }
46
47 #else /* !defined(CONFIG_440) */
48
49 static __inline__ void set_pit(unsigned long val)
50 {
51         asm volatile("mtpit %0" : : "r" (val));
52 }
53
54 static __inline__ void set_evpr(unsigned long val)
55 {
56         asm volatile("mtevpr %0" : : "r" (val));
57 }
58 #endif /* defined(CONFIG_440 */
59
60 int interrupt_init_cpu (unsigned *decrementer_count)
61 {
62         int vec;
63         unsigned long val;
64
65         /* decrementer is automatically reloaded */
66         *decrementer_count = 0;
67
68         /*
69          * Mark all irqs as free
70          */
71         for (vec = 0; vec < IRQ_MAX; vec++) {
72                 irq_vecs[vec].handler = NULL;
73                 irq_vecs[vec].arg = NULL;
74                 irq_vecs[vec].count = 0;
75         }
76
77 #ifdef CONFIG_4xx
78         /*
79          * Init PIT
80          */
81 #if defined(CONFIG_440)
82         val = mfspr( SPRN_TCR );
83         val &= (~0x04400000);           /* clear DIS & ARE */
84         mtspr( SPRN_TCR, val );
85         mtspr( SPRN_DEC, 0 );           /* Prevent exception after TSR clear*/
86         mtspr( SPRN_DECAR, 0 );         /* clear reload */
87         mtspr( SPRN_TSR, 0x08000000 );  /* clear DEC status */
88         val = gd->bd->bi_intfreq/1000;  /* 1 msec */
89         mtspr( SPRN_DECAR, val );               /* Set auto-reload value */
90         mtspr( SPRN_DEC, val );         /* Set inital val */
91 #else
92         set_pit(gd->bd->bi_intfreq / 1000);
93 #endif
94 #endif  /* CONFIG_4xx */
95
96 #ifdef CONFIG_ADCIOP
97         /*
98          * Init PIT
99          */
100         set_pit(66000);
101 #endif
102
103         /*
104          * Enable PIT
105          */
106         val = mfspr(SPRN_TCR);
107         val |= 0x04400000;
108         mtspr(SPRN_TCR, val);
109
110         /*
111          * Set EVPR to 0
112          */
113         set_evpr(0x00000000);
114
115         /*
116          * Call uic or xilinx_irq pic_enable
117          */
118         pic_enable();
119
120         return (0);
121 }
122
123 void timer_interrupt_cpu(struct pt_regs *regs)
124 {
125         /* nothing to do here */
126         return;
127 }
128
129 void interrupt_run_handler(int vec)
130 {
131         irq_vecs[vec].count++;
132
133         if (irq_vecs[vec].handler != NULL) {
134                 /* call isr */
135                 (*irq_vecs[vec].handler) (irq_vecs[vec].arg);
136         } else {
137                 pic_irq_disable(vec);
138                 printf("Masking bogus interrupt vector %d\n", vec);
139         }
140
141         pic_irq_ack(vec);
142         return;
143 }
144
145 void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
146 {
147         /*
148          * Print warning when replacing with a different irq vector
149          */
150         if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
151                 printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
152                        vec, (uint) handler, (uint) irq_vecs[vec].handler);
153         }
154         irq_vecs[vec].handler = handler;
155         irq_vecs[vec].arg = arg;
156
157         pic_irq_enable(vec);
158         return;
159 }
160
161 void irq_free_handler(int vec)
162 {
163         debug("Free interrupt for vector %d ==> %p\n",
164               vec, irq_vecs[vec].handler);
165
166         pic_irq_disable(vec);
167
168         irq_vecs[vec].handler = NULL;
169         irq_vecs[vec].arg = NULL;
170         return;
171 }
172
173 #if defined(CONFIG_CMD_IRQ)
174 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
175 {
176         int vec;
177
178         printf ("Interrupt-Information:\n");
179         printf ("Nr  Routine   Arg       Count\n");
180
181         for (vec = 0; vec < IRQ_MAX; vec++) {
182                 if (irq_vecs[vec].handler != NULL) {
183                         printf ("%02d  %08lx  %08lx  %d\n",
184                                 vec,
185                                 (ulong)irq_vecs[vec].handler,
186                                 (ulong)irq_vecs[vec].arg,
187                                 irq_vecs[vec].count);
188                 }
189         }
190
191         return 0;
192 }
193 #endif