2 * Shared interrupt handling code for IPR and INTC2 types of IRQs.
4 * Copyright (C) 2007 Magnus Damm
6 * Based on intc2.c and ipr.c
8 * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
9 * Copyright (C) 2000 Kazumoto Kojima
10 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
11 * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
12 * Copyright (C) 2005, 2006 Paul Mundt
14 * This file is subject to the terms and conditions of the GNU General Public
15 * License. See the file "COPYING" in the main directory of this archive
18 #include <linux/init.h>
19 #include <linux/irq.h>
20 #include <linux/module.h>
22 #include <linux/interrupt.h>
24 #define _INTC_MK(fn, idx, bit, value) \
25 ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
26 #define _INTC_FN(h) (h >> 24)
27 #define _INTC_VALUE(h) ((h >> 16) & 0xff)
28 #define _INTC_IDX(h) ((h >> 8) & 0xff)
29 #define _INTC_BIT(h) (h & 0xff)
31 #define _INTC_PTR(desc, member, data) \
32 (desc->member + _INTC_IDX(data))
34 static inline struct intc_desc
*get_intc_desc(unsigned int irq
)
36 struct irq_chip
*chip
= get_irq_chip(irq
);
37 return (void *)((char *)chip
- offsetof(struct intc_desc
, chip
));
40 static inline unsigned int set_field(unsigned int value
,
41 unsigned int field_value
,
45 value
&= ~(((1 << width
) - 1) << shift
);
46 value
|= field_value
<< shift
;
50 static inline unsigned int set_prio_field(struct intc_desc
*desc
,
52 unsigned int priority
,
55 unsigned int width
= _INTC_PTR(desc
, prio_regs
, data
)->field_width
;
57 return set_field(value
, priority
, width
, _INTC_BIT(data
));
60 static void disable_prio_16(struct intc_desc
*desc
, unsigned int data
)
62 unsigned long addr
= _INTC_PTR(desc
, prio_regs
, data
)->reg
;
64 ctrl_outw(set_prio_field(desc
, ctrl_inw(addr
), 0, data
), addr
);
67 static void enable_prio_16(struct intc_desc
*desc
, unsigned int data
)
69 unsigned long addr
= _INTC_PTR(desc
, prio_regs
, data
)->reg
;
70 unsigned int prio
= _INTC_VALUE(data
);
72 ctrl_outw(set_prio_field(desc
, ctrl_inw(addr
), prio
, data
), addr
);
75 static void disable_prio_32(struct intc_desc
*desc
, unsigned int data
)
77 unsigned long addr
= _INTC_PTR(desc
, prio_regs
, data
)->reg
;
79 ctrl_outl(set_prio_field(desc
, ctrl_inl(addr
), 0, data
), addr
);
82 static void enable_prio_32(struct intc_desc
*desc
, unsigned int data
)
84 unsigned long addr
= _INTC_PTR(desc
, prio_regs
, data
)->reg
;
85 unsigned int prio
= _INTC_VALUE(data
);
87 ctrl_outl(set_prio_field(desc
, ctrl_inl(addr
), prio
, data
), addr
);
90 static void disable_mask_8(struct intc_desc
*desc
, unsigned int data
)
92 ctrl_outb(1 << _INTC_BIT(data
),
93 _INTC_PTR(desc
, mask_regs
, data
)->set_reg
);
96 static void enable_mask_8(struct intc_desc
*desc
, unsigned int data
)
98 ctrl_outb(1 << _INTC_BIT(data
),
99 _INTC_PTR(desc
, mask_regs
, data
)->clr_reg
);
102 static void disable_mask_32(struct intc_desc
*desc
, unsigned int data
)
104 ctrl_outl(1 << _INTC_BIT(data
),
105 _INTC_PTR(desc
, mask_regs
, data
)->set_reg
);
108 static void enable_mask_32(struct intc_desc
*desc
, unsigned int data
)
110 ctrl_outl(1 << _INTC_BIT(data
),
111 _INTC_PTR(desc
, mask_regs
, data
)->clr_reg
);
114 enum { REG_FN_ERROR
=0,
115 REG_FN_MASK_8
, REG_FN_MASK_32
,
116 REG_FN_PRIO_16
, REG_FN_PRIO_32
};
119 void (*enable
)(struct intc_desc
*, unsigned int);
120 void (*disable
)(struct intc_desc
*, unsigned int);
122 [REG_FN_MASK_8
] = { enable_mask_8
, disable_mask_8
},
123 [REG_FN_MASK_32
] = { enable_mask_32
, disable_mask_32
},
124 [REG_FN_PRIO_16
] = { enable_prio_16
, disable_prio_16
},
125 [REG_FN_PRIO_32
] = { enable_prio_32
, disable_prio_32
},
128 static void intc_enable(unsigned int irq
)
130 struct intc_desc
*desc
= get_intc_desc(irq
);
131 unsigned int data
= (unsigned int) get_irq_chip_data(irq
);
133 intc_reg_fns
[_INTC_FN(data
)].enable(desc
, data
);
136 static void intc_disable(unsigned int irq
)
138 struct intc_desc
*desc
= get_intc_desc(irq
);
139 unsigned int data
= (unsigned int) get_irq_chip_data(irq
);
141 intc_reg_fns
[_INTC_FN(data
)].disable(desc
, data
);
144 static void set_sense_16(struct intc_desc
*desc
, unsigned int data
)
146 unsigned long addr
= _INTC_PTR(desc
, sense_regs
, data
)->reg
;
147 unsigned int width
= _INTC_PTR(desc
, sense_regs
, data
)->field_width
;
148 unsigned int bit
= _INTC_BIT(data
);
149 unsigned int value
= _INTC_VALUE(data
);
151 ctrl_outw(set_field(ctrl_inw(addr
), value
, width
, bit
), addr
);
154 static void set_sense_32(struct intc_desc
*desc
, unsigned int data
)
156 unsigned long addr
= _INTC_PTR(desc
, sense_regs
, data
)->reg
;
157 unsigned int width
= _INTC_PTR(desc
, sense_regs
, data
)->field_width
;
158 unsigned int bit
= _INTC_BIT(data
);
159 unsigned int value
= _INTC_VALUE(data
);
161 ctrl_outl(set_field(ctrl_inl(addr
), value
, width
, bit
), addr
);
164 #define VALID(x) (x | 0x80)
166 static unsigned char intc_irq_sense_table
[IRQ_TYPE_SENSE_MASK
+ 1] = {
167 [IRQ_TYPE_EDGE_FALLING
] = VALID(0),
168 [IRQ_TYPE_EDGE_RISING
] = VALID(1),
169 [IRQ_TYPE_LEVEL_LOW
] = VALID(2),
170 [IRQ_TYPE_LEVEL_HIGH
] = VALID(3),
173 static int intc_set_sense(unsigned int irq
, unsigned int type
)
175 struct intc_desc
*desc
= get_intc_desc(irq
);
176 unsigned char value
= intc_irq_sense_table
[type
& IRQ_TYPE_SENSE_MASK
];
177 unsigned int i
, j
, data
, bit
;
178 intc_enum enum_id
= 0;
180 for (i
= 0; i
< desc
->nr_vectors
; i
++) {
181 struct intc_vect
*vect
= desc
->vectors
+ i
;
183 if (evt2irq(vect
->vect
) != irq
)
186 enum_id
= vect
->enum_id
;
190 if (!enum_id
|| !value
)
195 for (i
= 0; i
< desc
->nr_sense_regs
; i
++) {
196 struct intc_sense_reg
*sr
= desc
->sense_regs
+ i
;
198 for (j
= 0; j
< ARRAY_SIZE(sr
->enum_ids
); j
++) {
199 if (sr
->enum_ids
[j
] != enum_id
)
202 bit
= sr
->reg_width
- ((j
+ 1) * sr
->field_width
);
203 data
= _INTC_MK(0, i
, bit
, value
);
205 switch(sr
->reg_width
) {
207 set_sense_16(desc
, data
);
210 set_sense_32(desc
, data
);
221 static unsigned int __init
intc_find_mask_handler(unsigned int width
)
225 return REG_FN_MASK_8
;
227 return REG_FN_MASK_32
;
234 static unsigned int __init
intc_find_prio_handler(unsigned int width
)
238 return REG_FN_PRIO_16
;
240 return REG_FN_PRIO_32
;
247 static intc_enum __init
intc_grp_id(struct intc_desc
*desc
, intc_enum enum_id
)
249 struct intc_group
*g
= desc
->groups
;
252 for (i
= 0; g
&& enum_id
&& i
< desc
->nr_groups
; i
++) {
253 g
= desc
->groups
+ i
;
255 for (j
= 0; g
->enum_ids
[j
]; j
++) {
256 if (g
->enum_ids
[j
] != enum_id
)
266 static unsigned int __init
intc_prio_value(struct intc_desc
*desc
,
267 intc_enum enum_id
, int do_grps
)
269 struct intc_prio
*p
= desc
->priorities
;
272 for (i
= 0; p
&& enum_id
&& i
< desc
->nr_priorities
; i
++) {
273 p
= desc
->priorities
+ i
;
275 if (p
->enum_id
!= enum_id
)
282 return intc_prio_value(desc
, intc_grp_id(desc
, enum_id
), 0);
284 /* default to the lowest priority possible if no priority is set
285 * - this needs to be at least 2 for 5-bit priorities on 7780
291 static unsigned int __init
intc_mask_data(struct intc_desc
*desc
,
292 intc_enum enum_id
, int do_grps
)
294 struct intc_mask_reg
*mr
= desc
->mask_regs
;
295 unsigned int i
, j
, fn
;
297 for (i
= 0; mr
&& enum_id
&& i
< desc
->nr_mask_regs
; i
++) {
298 mr
= desc
->mask_regs
+ i
;
300 for (j
= 0; j
< ARRAY_SIZE(mr
->enum_ids
); j
++) {
301 if (mr
->enum_ids
[j
] != enum_id
)
304 fn
= intc_find_mask_handler(mr
->reg_width
);
305 if (fn
== REG_FN_ERROR
)
308 return _INTC_MK(fn
, i
, (mr
->reg_width
- 1) - j
, 0);
313 return intc_mask_data(desc
, intc_grp_id(desc
, enum_id
), 0);
318 static unsigned int __init
intc_prio_data(struct intc_desc
*desc
,
319 intc_enum enum_id
, int do_grps
)
321 struct intc_prio_reg
*pr
= desc
->prio_regs
;
322 unsigned int i
, j
, fn
, bit
, prio
;
324 for (i
= 0; pr
&& enum_id
&& i
< desc
->nr_prio_regs
; i
++) {
325 pr
= desc
->prio_regs
+ i
;
327 for (j
= 0; j
< ARRAY_SIZE(pr
->enum_ids
); j
++) {
328 if (pr
->enum_ids
[j
] != enum_id
)
331 fn
= intc_find_prio_handler(pr
->reg_width
);
332 if (fn
== REG_FN_ERROR
)
335 prio
= intc_prio_value(desc
, enum_id
, 1);
336 bit
= pr
->reg_width
- ((j
+ 1) * pr
->field_width
);
340 return _INTC_MK(fn
, i
, bit
, prio
);
345 return intc_prio_data(desc
, intc_grp_id(desc
, enum_id
), 0);
350 static void __init
intc_register_irq(struct intc_desc
*desc
, intc_enum enum_id
,
353 unsigned int data
[2], primary
;
355 /* Prefer single interrupt source bitmap over other combinations:
356 * 1. bitmap, single interrupt source
357 * 2. priority, single interrupt source
358 * 3. bitmap, multiple interrupt sources (groups)
359 * 4. priority, multiple interrupt sources (groups)
362 data
[0] = intc_mask_data(desc
, enum_id
, 0);
363 data
[1] = intc_prio_data(desc
, enum_id
, 0);
366 if (!data
[0] && data
[1])
369 data
[0] = data
[0] ? data
[0] : intc_mask_data(desc
, enum_id
, 1);
370 data
[1] = data
[1] ? data
[1] : intc_prio_data(desc
, enum_id
, 1);
375 BUG_ON(!data
[primary
]); /* must have primary masking method */
377 disable_irq_nosync(irq
);
378 set_irq_chip_and_handler_name(irq
, &desc
->chip
,
379 handle_level_irq
, "level");
380 set_irq_chip_data(irq
, (void *)data
[primary
]);
382 /* enable secondary masking method if present */
384 intc_reg_fns
[_INTC_FN(data
[!primary
])].enable(desc
,
387 /* irq should be disabled by default */
388 desc
->chip
.mask(irq
);
391 void __init
register_intc_controller(struct intc_desc
*desc
)
395 desc
->chip
.mask
= intc_disable
;
396 desc
->chip
.unmask
= intc_enable
;
397 desc
->chip
.mask_ack
= intc_disable
;
398 desc
->chip
.set_type
= intc_set_sense
;
400 for (i
= 0; i
< desc
->nr_vectors
; i
++) {
401 struct intc_vect
*vect
= desc
->vectors
+ i
;
403 intc_register_irq(desc
, vect
->enum_id
, evt2irq(vect
->vect
));
This page took 0.041662 seconds and 5 git commands to generate.