diff options
| author | Magnus Damm <damm@igel.co.jp> | 2007-08-03 01:25:32 -0400 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2007-09-20 22:57:47 -0400 |
| commit | 51da64264b8d59a1e5fceebd94a975690b70b086 (patch) | |
| tree | bb3042c8e14f162bda662ec9e93c807aef37de05 | |
| parent | 2635e8558a7ec0002724e3da8c0a221d2c08af33 (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>
| -rw-r--r-- | arch/sh/kernel/cpu/irq/intc.c | 73 | ||||
| -rw-r--r-- | include/asm-sh/hw_irq.h | 1 |
2 files changed, 63 insertions, 11 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c index 9345a7130e9e..a25f70dd6ad7 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 | ||
| 90 | static void disable_mask_8(struct intc_desc *desc, unsigned int data) | 90 | static 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 | ||
| 96 | static void enable_mask_8(struct intc_desc *desc, unsigned int data) | 96 | static 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 | ||
| 102 | static void disable_mask_32(struct intc_desc *desc, unsigned int data) | 102 | static 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 | ||
| 108 | static void enable_mask_32(struct intc_desc *desc, unsigned int data) | 108 | static 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 | ||
| 114 | static 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 | |||
| 121 | static 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 | |||
| 128 | static 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 | |||
| 135 | static 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 | |||
| 114 | enum { REG_FN_ERROR=0, | 142 | enum { 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 | ||
| 118 | static struct { | 147 | static 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 | ||
| 221 | static unsigned int __init intc_find_mask_handler(unsigned int width) | 252 | static 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 | ||
| 278 | static 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 | |||
| 247 | static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) | 291 | static 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 | ||
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h index 8f5bf98d053e..9f55c2dc1b50 100644 --- a/include/asm-sh/hw_irq.h +++ b/include/asm-sh/hw_irq.h | |||
| @@ -49,6 +49,7 @@ struct intc_vect { | |||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | #define INTC_VECT(enum_id, vect) { enum_id, vect } | 51 | #define INTC_VECT(enum_id, vect) { enum_id, vect } |
| 52 | #define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq)) | ||
| 52 | 53 | ||
| 53 | struct intc_prio { | 54 | struct intc_prio { |
| 54 | intc_enum enum_id; | 55 | intc_enum enum_id; |
