1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4 *
5 *  arch/mips/ddb5xxx/ddb5477/irq_5477.c
6 *     This file defines the irq handler for Vrc5477.
7 *
8 * This program is free software; you can redistribute  it and/or modify it
9 * under  the terms of  the GNU General  Public License as published by the
10 * Free Software Foundation;  either version 2 of the  License, or (at your
11 * option) any later version.
12 *
13 */
14
15/*
16 * Vrc5477 defines 32 IRQs.
17 *
18 * This file exports one function:
19 *	vrc5477_irq_init(u32 irq_base);
20 */
21
22#include <linux/interrupt.h>
23#include <linux/types.h>
24#include <linux/ptrace.h>
25
26#include <asm/debug.h>
27
28#include <asm/ddb5xxx/ddb5xxx.h>
29
30/* number of total irqs supported by Vrc5477 */
31#define	NUM_5477_IRQ		32
32
33static int vrc5477_irq_base = -1;
34
35
36static void
37vrc5477_irq_enable(unsigned int irq)
38{
39	db_assert(vrc5477_irq_base != -1);
40	db_assert(irq >= vrc5477_irq_base);
41	db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ);
42
43	ll_vrc5477_irq_enable(irq - vrc5477_irq_base);
44}
45
46static void
47vrc5477_irq_disable(unsigned int irq)
48{
49	db_assert(vrc5477_irq_base != -1);
50	db_assert(irq >= vrc5477_irq_base);
51	db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ);
52
53	ll_vrc5477_irq_disable(irq - vrc5477_irq_base);
54}
55
56static void
57vrc5477_irq_ack(unsigned int irq)
58{
59	db_assert(vrc5477_irq_base != -1);
60	db_assert(irq >= vrc5477_irq_base);
61	db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ);
62
63	/* clear the interrupt bit */
64	/* some irqs require the driver to clear the sources */
65	ddb_out32(DDB_INTCLR32, 1 << (irq - vrc5477_irq_base));
66
67	/* disable interrupt - some handler will re-enable the irq
68	 * and if the interrupt is leveled, we will have infinite loop
69	 */
70	ll_vrc5477_irq_disable(irq - vrc5477_irq_base);
71}
72
73static void
74vrc5477_irq_end(unsigned int irq)
75{
76	db_assert(vrc5477_irq_base != -1);
77	db_assert(irq >= vrc5477_irq_base);
78	db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ);
79
80	if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
81		ll_vrc5477_irq_enable( irq - vrc5477_irq_base);
82}
83
84struct irq_chip vrc5477_irq_controller = {
85	.name = "vrc5477_irq",
86	.ack = vrc5477_irq_ack,
87	.mask = vrc5477_irq_disable,
88	.mask_ack = vrc5477_irq_ack,
89	.unmask = vrc5477_irq_enable,
90	.end = vrc5477_irq_end
91};
92
93void __init vrc5477_irq_init(u32 irq_base)
94{
95	u32 i;
96
97	for (i= irq_base; i< irq_base+ NUM_5477_IRQ; i++)
98		set_irq_chip(i, &vrc5477_irq_controller);
99
100	vrc5477_irq_base = irq_base;
101}
102
103void ll_vrc5477_irq_route(int vrc5477_irq, int ip)
104{
105	u32 reg_value;
106	u32 reg_bitmask;
107	u32 reg_index;
108
109	db_assert(vrc5477_irq >= 0);
110	db_assert(vrc5477_irq < NUM_5477_IRQ);
111	db_assert(ip >= 0);
112	db_assert((ip < 5) || (ip == 6));
113
114	reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
115	reg_value = ddb_in32(reg_index);
116	reg_bitmask = 7 << (vrc5477_irq % 8 * 4);
117	reg_value &= ~reg_bitmask;
118	reg_value |= ip << (vrc5477_irq % 8 * 4);
119	ddb_out32(reg_index, reg_value);
120}
121
122void ll_vrc5477_irq_enable(int vrc5477_irq)
123{
124	u32 reg_value;
125	u32 reg_bitmask;
126	u32 reg_index;
127
128	db_assert(vrc5477_irq >= 0);
129	db_assert(vrc5477_irq < NUM_5477_IRQ);
130
131	reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
132	reg_value = ddb_in32(reg_index);
133	reg_bitmask = 8 << (vrc5477_irq % 8 * 4);
134	db_assert((reg_value & reg_bitmask) == 0);
135	ddb_out32(reg_index, reg_value | reg_bitmask);
136}
137
138void ll_vrc5477_irq_disable(int vrc5477_irq)
139{
140	u32 reg_value;
141	u32 reg_bitmask;
142	u32 reg_index;
143
144	db_assert(vrc5477_irq >= 0);
145	db_assert(vrc5477_irq < NUM_5477_IRQ);
146
147	reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
148	reg_value = ddb_in32(reg_index);
149	reg_bitmask = 8 << (vrc5477_irq % 8 * 4);
150
151	/* we assert that the interrupt is enabled (perhaps over-zealous) */
152	db_assert( (reg_value & reg_bitmask) != 0);
153	ddb_out32(reg_index, reg_value & ~reg_bitmask);
154}
155