84ab5adb946a6f9375d7074784543513f9aec8be
[linux-flexiantxendom0-3.2.10.git] / arch / h8300 / platform / h8s / ints.c
1 /*
2  * linux/arch/h8300/platform/h8s/ints.c
3  *
4  * Yoshinori Sato <ysato@users.sourceforge.jp>
5  *
6  * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file COPYING in the main directory of this archive
10  * for more details.
11  *
12  * Copyright 1996 Roman Zippel
13  * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
14  */
15
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/kernel_stat.h>
21 #include <linux/seq_file.h>
22 #include <linux/init.h>
23 #include <linux/bootmem.h>
24 #include <linux/random.h>
25
26 #include <asm/system.h>
27 #include <asm/irq.h>
28 #include <asm/traps.h>
29 #include <asm/io.h>
30 #include <asm/setup.h>
31 #include <asm/gpio.h>
32 #include <asm/hardirq.h>
33 #include <asm/regs267x.h>
34 #include <asm/errno.h>
35
36 /*
37  * This structure has only 4 elements for speed reasons
38  */
39 typedef struct irq_handler {
40         irqreturn_t (*handler)(int, void *, struct pt_regs *);
41         int         flags;
42         int         count;
43         void        *dev_id;
44         const char  *devname;
45 } irq_handler_t;
46
47 static irq_handler_t *irq_list[NR_IRQS];
48
49 /* IRQ pin assignment */
50 struct irq_pins {
51         unsigned char port_no;
52         unsigned char bit_no;
53 };
54 /* ISTR = 0 */
55 const static struct irq_pins irq_assign_table0[16]={
56         {H8300_GPIO_P5,H8300_GPIO_B0},{H8300_GPIO_P5,H8300_GPIO_B1},
57         {H8300_GPIO_P5,H8300_GPIO_B2},{H8300_GPIO_P5,H8300_GPIO_B3},
58         {H8300_GPIO_P5,H8300_GPIO_B4},{H8300_GPIO_P5,H8300_GPIO_B5},
59         {H8300_GPIO_P5,H8300_GPIO_B6},{H8300_GPIO_P5,H8300_GPIO_B7},
60         {H8300_GPIO_P6,H8300_GPIO_B0},{H8300_GPIO_P6,H8300_GPIO_B1},
61         {H8300_GPIO_P6,H8300_GPIO_B2},{H8300_GPIO_P6,H8300_GPIO_B3},
62         {H8300_GPIO_P6,H8300_GPIO_B4},{H8300_GPIO_P6,H8300_GPIO_B5},
63         {H8300_GPIO_PF,H8300_GPIO_B1},{H8300_GPIO_PF,H8300_GPIO_B2},
64 };
65 /* ISTR = 1 */
66 const static struct irq_pins irq_assign_table1[16]={
67         {H8300_GPIO_P8,H8300_GPIO_B0},{H8300_GPIO_P8,H8300_GPIO_B1},
68         {H8300_GPIO_P8,H8300_GPIO_B2},{H8300_GPIO_P8,H8300_GPIO_B3},
69         {H8300_GPIO_P8,H8300_GPIO_B4},{H8300_GPIO_P8,H8300_GPIO_B5},
70         {H8300_GPIO_PH,H8300_GPIO_B2},{H8300_GPIO_PH,H8300_GPIO_B3},
71         {H8300_GPIO_P2,H8300_GPIO_B0},{H8300_GPIO_P2,H8300_GPIO_B1},
72         {H8300_GPIO_P2,H8300_GPIO_B2},{H8300_GPIO_P2,H8300_GPIO_B3},
73         {H8300_GPIO_P2,H8300_GPIO_B4},{H8300_GPIO_P2,H8300_GPIO_B5},
74         {H8300_GPIO_P2,H8300_GPIO_B6},{H8300_GPIO_P2,H8300_GPIO_B7},
75 };
76
77 static short use_kmalloc = 0;
78
79 extern unsigned long *interrupt_redirect_table;
80
81 #define CPU_VECTOR ((unsigned long *)0x000000)
82 #define ADDR_MASK (0xffffff)
83
84 static inline unsigned long *get_vector_address(void)
85 {
86         volatile unsigned long *rom_vector = CPU_VECTOR;
87         unsigned long base,tmp;
88         int vec_no;
89
90         base = rom_vector[EXT_IRQ0] & ADDR_MASK;
91         
92         /* check romvector format */
93         for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ15; vec_no++) {
94                 if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
95                         return NULL;
96         }
97
98         /* ramvector base address */
99         base -= EXT_IRQ0*4;
100
101         /* writerble check */
102         tmp = ~(*(unsigned long *)base);
103         (*(unsigned long *)base) = tmp;
104         if ((*(unsigned long *)base) != tmp)
105                 return NULL;
106         return (unsigned long *)base;
107 }
108
109 void __init init_IRQ(void)
110 {
111 #if defined(CONFIG_RAMKERNEL)
112         int i;
113         unsigned long *ramvec,*ramvec_p;
114         unsigned long break_vec;
115
116         ramvec = get_vector_address();
117         if (ramvec == NULL)
118                 panic("interrupt vector serup failed.");
119         else
120                 printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec);
121
122 #if defined(CONFIG_GDB_DEBUG)
123         /* save orignal break vector */
124         break_vec = ramvec[TRAP3_VEC];
125 #else
126         break_vec = VECTOR(trace_break);
127 #endif
128
129         /* create redirect table */
130         for (ramvec_p = ramvec, i = 0; i < NR_IRQS; i++)
131                 *ramvec_p++ = REDIRECT(interrupt_entry);
132
133         /* set special vector */
134         ramvec[TRAP0_VEC] = VECTOR(system_call);
135         ramvec[TRAP3_VEC] = break_vec;
136         interrupt_redirect_table = ramvec;
137 #ifdef DUMP_VECTOR
138         ramvec_p = ramvec;
139         for (i = 0; i < NR_IRQS; i++) {
140                 if ((i % 8) == 0)
141                         printk("\n%p: ",ramvec_p);
142                 printk("%p ",*ramvec_p);
143                 ramvec_p++;
144         }
145         printk("\n");
146 #endif
147 #endif
148 }
149
150 int request_irq(unsigned int irq,
151                 irqreturn_t (*handler)(int, void *, struct pt_regs *),
152                 unsigned long flags, const char *devname, void *dev_id)
153 {
154         unsigned short ptn = 1 << (irq - EXT_IRQ0);
155         irq_handler_t *irq_handle;
156         if (irq < 0 || irq >= NR_IRQS) {
157                 printk("Incorrect IRQ %d from %s\n", irq, devname);
158                 return -EINVAL;
159         }
160         if (irq_list[irq])
161                 return -EBUSY; /* already used */
162         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) {
163                 /* initialize IRQ pin */
164                 unsigned int port_no,bit_no;
165                 if (*(volatile unsigned short *)ITSR & ptn) {
166                         port_no = irq_assign_table1[irq - EXT_IRQ0].port_no;
167                         bit_no = irq_assign_table1[irq - EXT_IRQ0].bit_no;
168                 } else {
169                         port_no = irq_assign_table0[irq - EXT_IRQ0].port_no;
170                         bit_no = irq_assign_table0[irq - EXT_IRQ0].bit_no;
171                 }
172                 if (H8300_GPIO_RESERVE(port_no, bit_no) == 0)
173                         return -EBUSY;                   /* pin already use */
174                 H8300_GPIO_DDR(port_no, bit_no, H8300_GPIO_INPUT);
175                 *(volatile unsigned short *)ISR &= ~ptn; /* ISR clear */
176         }               
177
178         if (use_kmalloc)
179                 irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
180         else {
181                 irq_handle = alloc_bootmem(sizeof(irq_handler_t));
182                 (unsigned long)irq_handle |= 0x80000000; /* bootmem allocater */
183         }
184
185         if (irq_handle == NULL)
186                 return -ENOMEM;
187
188         irq_handle->handler = handler;
189         irq_handle->flags   = flags;
190         irq_handle->count   = 0;
191         irq_handle->dev_id  = dev_id;
192         irq_handle->devname = devname;
193         irq_list[irq] = irq_handle;
194         if (irq_handle->flags & SA_SAMPLE_RANDOM)
195                 rand_initialize_irq(irq);
196         
197         /* enable interrupt */
198         /* compatible i386  */
199         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
200                 *(volatile unsigned short *)IER |= ptn;
201         return 0;
202 }
203
204 EXPORT_SYMBOL(request_irq);
205
206 void free_irq(unsigned int irq, void *dev_id)
207 {
208         if (irq >= NR_IRQS)
209                 return;
210         if (irq_list[irq]->dev_id != dev_id)
211                 printk("%s: Removing probably wrong IRQ %d from %s\n",
212                        __FUNCTION__, irq, irq_list[irq]->devname);
213         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) {
214                 /* disable interrupt & release IRQ pin */
215                 unsigned short port_no,bit_no;
216                 *(volatile unsigned short *)ISR &= ~(1 << (irq - EXT_IRQ0));
217                 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0);
218                 if (*(volatile unsigned short *)ITSR & (1 << (irq - EXT_IRQ0))) {
219                         port_no = irq_assign_table1[irq - EXT_IRQ0].port_no;
220                         bit_no = irq_assign_table1[irq - EXT_IRQ0].bit_no;
221                 } else {
222                         port_no = irq_assign_table0[irq - EXT_IRQ0].port_no;
223                         bit_no = irq_assign_table0[irq - EXT_IRQ0].bit_no;
224                 }
225                 H8300_GPIO_FREE(port_no, bit_no);
226         }
227         if (((unsigned long)irq_list[irq] & 0x80000000) == 0) {
228                 kfree(irq_list[irq]);
229                 irq_list[irq] = NULL;
230         }
231 }
232
233 EXPORT_SYMBOL(free_irq);
234
235 unsigned long probe_irq_on (void)
236 {
237         return 0;
238 }
239
240 EXPORT_SYMBOL(probe_irq_on);
241
242 int probe_irq_off (unsigned long irqs)
243 {
244         return 0;
245 }
246
247 EXPORT_SYMBOL(probe_irq_off);
248
249 void enable_irq(unsigned int irq)
250 {
251         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
252                 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0);
253 }
254
255 void disable_irq(unsigned int irq)
256 {
257         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
258                 *(volatile unsigned short *)IER &= ~(1 << (irq - EXT_IRQ0));
259 }
260
261 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
262 {
263         irq_enter();
264         /* ISR clear       */
265         /* compatible i386 */
266         if (vec >= EXT_IRQ0 && vec <= EXT_IRQ15)
267                 *(volatile unsigned short *)ISR &= ~(1 << (vec - EXT_IRQ0));
268         if (vec < NR_IRQS) {
269                 if (irq_list[vec]) {
270                         irq_list[vec]->handler(vec, irq_list[vec]->dev_id, fp);
271                         irq_list[vec]->count++;
272                         if (irq_list[vec]->flags & SA_SAMPLE_RANDOM)
273                                 add_interrupt_randomness(vec);
274                 }
275         } else {
276                 BUG();
277         }
278         irq_exit();
279 }
280
281 int show_interrupts(struct seq_file *p, void *v)
282 {
283         int i;
284
285         for (i = 0; i < NR_IRQS; i++) {
286                 if (irq_list[i]) {
287                         seq_printf(p, "%3d: %10u ",i,irq_list[i]->count);
288                         seq_printf(p, "%s\n", irq_list[i]->devname);
289                 }
290         }
291
292         return 0;
293 }
294
295 void init_irq_proc(void)
296 {
297 }
298
299 static int __init enable_kmalloc(void)
300 {
301         use_kmalloc = 1;
302         return 0;
303 }
304 core_initcall(enable_kmalloc);