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