aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/irq
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2007-08-03 01:25:32 -0400
committerPaul Mundt <lethal@linux-sh.org>2007-09-20 22:57:47 -0400
commit51da64264b8d59a1e5fceebd94a975690b70b086 (patch)
treebb3042c8e14f162bda662ec9e93c807aef37de05 /arch/sh/kernel/cpu/irq
parent2635e8558a7ec0002724e3da8c0a221d2c08af33 (diff)
sh: intc - add single bitmap register support
This patch adds single bitmap register support to intc. The current code only handles 16 and 32 bit registers where a set bit means interrupt enabled, but this is easy to extend in the future. The INTC_IRQ() macro is also added to provide a way to hook in interrupt controllers for FPGAs in boards or companion chips. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c73
1 files changed, 62 insertions, 11 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 9345a7130e9..a25f70dd6ad 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -87,40 +87,71 @@ static void enable_prio_32(struct intc_desc *desc, unsigned int data)
87 ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr); 87 ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
88} 88}
89 89
90static void disable_mask_8(struct intc_desc *desc, unsigned int data) 90static void write_set_reg_8(struct intc_desc *desc, unsigned int data)
91{ 91{
92 ctrl_outb(1 << _INTC_BIT(data), 92 ctrl_outb(1 << _INTC_BIT(data),
93 _INTC_PTR(desc, mask_regs, data)->set_reg); 93 _INTC_PTR(desc, mask_regs, data)->set_reg);
94} 94}
95 95
96static void enable_mask_8(struct intc_desc *desc, unsigned int data) 96static void write_clr_reg_8(struct intc_desc *desc, unsigned int data)
97{ 97{
98 ctrl_outb(1 << _INTC_BIT(data), 98 ctrl_outb(1 << _INTC_BIT(data),
99 _INTC_PTR(desc, mask_regs, data)->clr_reg); 99 _INTC_PTR(desc, mask_regs, data)->clr_reg);
100} 100}
101 101
102static void disable_mask_32(struct intc_desc *desc, unsigned int data) 102static void write_set_reg_32(struct intc_desc *desc, unsigned int data)
103{ 103{
104 ctrl_outl(1 << _INTC_BIT(data), 104 ctrl_outl(1 << _INTC_BIT(data),
105 _INTC_PTR(desc, mask_regs, data)->set_reg); 105 _INTC_PTR(desc, mask_regs, data)->set_reg);
106} 106}
107 107
108static void enable_mask_32(struct intc_desc *desc, unsigned int data) 108static void write_clr_reg_32(struct intc_desc *desc, unsigned int data)
109{ 109{
110 ctrl_outl(1 << _INTC_BIT(data), 110 ctrl_outl(1 << _INTC_BIT(data),
111 _INTC_PTR(desc, mask_regs, data)->clr_reg); 111 _INTC_PTR(desc, mask_regs, data)->clr_reg);
112} 112}
113 113
114static void or_set_reg_16(struct intc_desc *desc, unsigned int data)
115{
116 unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg;
117
118 ctrl_outw(ctrl_inw(addr) | 1 << _INTC_BIT(data), addr);
119}
120
121static void and_set_reg_16(struct intc_desc *desc, unsigned int data)
122{
123 unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg;
124
125 ctrl_outw(ctrl_inw(addr) & ~(1 << _INTC_BIT(data)), addr);
126}
127
128static void or_set_reg_32(struct intc_desc *desc, unsigned int data)
129{
130 unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg;
131
132 ctrl_outl(ctrl_inl(addr) | 1 << _INTC_BIT(data), addr);
133}
134
135static void and_set_reg_32(struct intc_desc *desc, unsigned int data)
136{
137 unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg;
138
139 ctrl_outl(ctrl_inl(addr) & ~(1 << _INTC_BIT(data)), addr);
140}
141
114enum { REG_FN_ERROR=0, 142enum { REG_FN_ERROR=0,
115 REG_FN_MASK_8, REG_FN_MASK_32, 143 REG_FN_DUAL_8, REG_FN_DUAL_32,
144 REG_FN_ENA_16, REG_FN_ENA_32,
116 REG_FN_PRIO_16, REG_FN_PRIO_32 }; 145 REG_FN_PRIO_16, REG_FN_PRIO_32 };
117 146
118static struct { 147static struct {
119 void (*enable)(struct intc_desc *, unsigned int); 148 void (*enable)(struct intc_desc *, unsigned int);
120 void (*disable)(struct intc_desc *, unsigned int); 149 void (*disable)(struct intc_desc *, unsigned int);
121} intc_reg_fns[] = { 150} intc_reg_fns[] = {
122 [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 }, 151 [REG_FN_DUAL_8] = { write_clr_reg_8, write_set_reg_8 },
123 [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 }, 152 [REG_FN_DUAL_32] = { write_clr_reg_32, write_set_reg_32 },
153 [REG_FN_ENA_16] = { or_set_reg_16, and_set_reg_16 },
154 [REG_FN_ENA_32] = { or_set_reg_32, and_set_reg_32 },
124 [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 }, 155 [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
125 [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 }, 156 [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
126}; 157};
@@ -218,13 +249,13 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
218 return -EINVAL; 249 return -EINVAL;
219} 250}
220 251
221static unsigned int __init intc_find_mask_handler(unsigned int width) 252static unsigned int __init intc_find_dual_handler(unsigned int width)
222{ 253{
223 switch (width) { 254 switch (width) {
224 case 8: 255 case 8:
225 return REG_FN_MASK_8; 256 return REG_FN_DUAL_8;
226 case 32: 257 case 32:
227 return REG_FN_MASK_32; 258 return REG_FN_DUAL_32;
228 } 259 }
229 260
230 BUG(); 261 BUG();
@@ -244,6 +275,19 @@ static unsigned int __init intc_find_prio_handler(unsigned int width)
244 return REG_FN_ERROR; 275 return REG_FN_ERROR;
245} 276}
246 277
278static unsigned int __init intc_find_ena_handler(unsigned int width)
279{
280 switch (width) {
281 case 16:
282 return REG_FN_ENA_16;
283 case 32:
284 return REG_FN_ENA_32;
285 }
286
287 BUG();
288 return REG_FN_ERROR;
289}
290
247static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) 291static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
248{ 292{
249 struct intc_group *g = desc->groups; 293 struct intc_group *g = desc->groups;
@@ -301,7 +345,14 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
301 if (mr->enum_ids[j] != enum_id) 345 if (mr->enum_ids[j] != enum_id)
302 continue; 346 continue;
303 347
304 fn = intc_find_mask_handler(mr->reg_width); 348 switch (mr->clr_reg) {
349 case 1: /* 1 = enabled interrupt - "enable" register */
350 fn = intc_find_ena_handler(mr->reg_width);
351 break;
352 default:
353 fn = intc_find_dual_handler(mr->reg_width);
354 }
355
305 if (fn == REG_FN_ERROR) 356 if (fn == REG_FN_ERROR)
306 return 0; 357 return 0;
307 358