Linux-2.6.12-rc2
[linux-2.6.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 #include <linux/hardirq.h>
26
27 #include <asm/system.h>
28 #include <asm/irq.h>
29 #include <asm/traps.h>
30 #include <asm/io.h>
31 #include <asm/setup.h>
32 #include <asm/gpio.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                 /* use bootmem allocater */
182                 irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
183                 irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000);
184         }
185
186         if (irq_handle == NULL)
187                 return -ENOMEM;
188
189         irq_handle->handler = handler;
190         irq_handle->flags   = flags;
191         irq_handle->count   = 0;
192         irq_handle->dev_id  = dev_id;
193         irq_handle->devname = devname;
194         irq_list[irq] = irq_handle;
195         if (irq_handle->flags & SA_SAMPLE_RANDOM)
196                 rand_initialize_irq(irq);
197         
198         /* enable interrupt */
199         /* compatible i386  */
200         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
201                 *(volatile unsigned short *)IER |= ptn;
202         return 0;
203 }
204
205 EXPORT_SYMBOL(request_irq);
206
207 void free_irq(unsigned int irq, void *dev_id)
208 {
209         if (irq >= NR_IRQS)
210                 return;
211         if (irq_list[irq]->dev_id != dev_id)
212                 printk("%s: Removing probably wrong IRQ %d from %s\n",
213                        __FUNCTION__, irq, irq_list[irq]->devname);
214         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) {
215                 /* disable interrupt & release IRQ pin */
216                 unsigned short port_no,bit_no;
217                 *(volatile unsigned short *)ISR &= ~(1 << (irq - EXT_IRQ0));
218                 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0);
219                 if (*(volatile unsigned short *)ITSR & (1 << (irq - EXT_IRQ0))) {
220                         port_no = irq_assign_table1[irq - EXT_IRQ0].port_no;
221                         bit_no = irq_assign_table1[irq - EXT_IRQ0].bit_no;
222                 } else {
223                         port_no = irq_assign_table0[irq - EXT_IRQ0].port_no;
224                         bit_no = irq_assign_table0[irq - EXT_IRQ0].bit_no;
225                 }
226                 H8300_GPIO_FREE(port_no, bit_no);
227         }
228         if (((unsigned long)irq_list[irq] & 0x80000000) == 0) {
229                 kfree(irq_list[irq]);
230                 irq_list[irq] = NULL;
231         }
232 }
233
234 EXPORT_SYMBOL(free_irq);
235
236 unsigned long probe_irq_on (void)
237 {
238         return 0;
239 }
240
241 EXPORT_SYMBOL(probe_irq_on);
242
243 int probe_irq_off (unsigned long irqs)
244 {
245         return 0;
246 }
247
248 EXPORT_SYMBOL(probe_irq_off);
249
250 void enable_irq(unsigned int irq)
251 {
252         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
253                 *(volatile unsigned short *)IER |= 1 << (irq - EXT_IRQ0);
254 }
255
256 void disable_irq(unsigned int irq)
257 {
258         if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)
259                 *(volatile unsigned short *)IER &= ~(1 << (irq - EXT_IRQ0));
260 }
261
262 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
263 {
264         irq_enter();
265         /* ISR clear       */
266         /* compatible i386 */
267         if (vec >= EXT_IRQ0 && vec <= EXT_IRQ15)
268                 *(volatile unsigned short *)ISR &= ~(1 << (vec - EXT_IRQ0));
269         if (vec < NR_IRQS) {
270                 if (irq_list[vec]) {
271                         irq_list[vec]->handler(vec, irq_list[vec]->dev_id, fp);
272                         irq_list[vec]->count++;
273                         if (irq_list[vec]->flags & SA_SAMPLE_RANDOM)
274                                 add_interrupt_randomness(vec);
275                 }
276         } else {
277                 BUG();
278         }
279         irq_exit();
280 }
281
282 int show_interrupts(struct seq_file *p, void *v)
283 {
284         int i = *(loff_t *) v;
285
286         if ((i < NR_IRQS) && (irq_list[i] !=NULL)) {
287                 seq_printf(p, "%3d: %10u ",i,irq_list[i]->count);
288                 seq_printf(p, "%s\n", irq_list[i]->devname);
289         }
290
291         return 0;
292 }
293
294 void init_irq_proc(void)
295 {
296 }
297
298 static int __init enable_kmalloc(void)
299 {
300         use_kmalloc = 1;
301         return 0;
302 }
303 core_initcall(enable_kmalloc);