diff options
author | Magnus Damm <damm@igel.co.jp> | 2007-08-03 14:25:32 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2007-09-21 11:57:47 +0900 |
commit | 51da64264b8d59a1e5fceebd94a975690b70b086 (patch) | |
tree | bb3042c8e14f162bda662ec9e93c807aef37de05 /arch/sh | |
parent | 2635e8558a7ec0002724e3da8c0a221d2c08af33 (diff) | |
download | op-kernel-dev-51da64264b8d59a1e5fceebd94a975690b70b086.zip op-kernel-dev-51da64264b8d59a1e5fceebd94a975690b70b086.tar.gz |
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')
-rw-r--r-- | arch/sh/kernel/cpu/irq/intc.c | 73 |
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 9345a71..a25f70d 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) ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr); } -static void disable_mask_8(struct intc_desc *desc, unsigned int data) +static void write_set_reg_8(struct intc_desc *desc, unsigned int data) { ctrl_outb(1 << _INTC_BIT(data), _INTC_PTR(desc, mask_regs, data)->set_reg); } -static void enable_mask_8(struct intc_desc *desc, unsigned int data) +static void write_clr_reg_8(struct intc_desc *desc, unsigned int data) { ctrl_outb(1 << _INTC_BIT(data), _INTC_PTR(desc, mask_regs, data)->clr_reg); } -static void disable_mask_32(struct intc_desc *desc, unsigned int data) +static void write_set_reg_32(struct intc_desc *desc, unsigned int data) { ctrl_outl(1 << _INTC_BIT(data), _INTC_PTR(desc, mask_regs, data)->set_reg); } -static void enable_mask_32(struct intc_desc *desc, unsigned int data) +static void write_clr_reg_32(struct intc_desc *desc, unsigned int data) { ctrl_outl(1 << _INTC_BIT(data), _INTC_PTR(desc, mask_regs, data)->clr_reg); } +static void or_set_reg_16(struct intc_desc *desc, unsigned int data) +{ + unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg; + + ctrl_outw(ctrl_inw(addr) | 1 << _INTC_BIT(data), addr); +} + +static void and_set_reg_16(struct intc_desc *desc, unsigned int data) +{ + unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg; + + ctrl_outw(ctrl_inw(addr) & ~(1 << _INTC_BIT(data)), addr); +} + +static void or_set_reg_32(struct intc_desc *desc, unsigned int data) +{ + unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg; + + ctrl_outl(ctrl_inl(addr) | 1 << _INTC_BIT(data), addr); +} + +static void and_set_reg_32(struct intc_desc *desc, unsigned int data) +{ + unsigned long addr = _INTC_PTR(desc, mask_regs, data)->set_reg; + + ctrl_outl(ctrl_inl(addr) & ~(1 << _INTC_BIT(data)), addr); +} + enum { REG_FN_ERROR=0, - REG_FN_MASK_8, REG_FN_MASK_32, + REG_FN_DUAL_8, REG_FN_DUAL_32, + REG_FN_ENA_16, REG_FN_ENA_32, REG_FN_PRIO_16, REG_FN_PRIO_32 }; static struct { void (*enable)(struct intc_desc *, unsigned int); void (*disable)(struct intc_desc *, unsigned int); } intc_reg_fns[] = { - [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 }, - [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 }, + [REG_FN_DUAL_8] = { write_clr_reg_8, write_set_reg_8 }, + [REG_FN_DUAL_32] = { write_clr_reg_32, write_set_reg_32 }, + [REG_FN_ENA_16] = { or_set_reg_16, and_set_reg_16 }, + [REG_FN_ENA_32] = { or_set_reg_32, and_set_reg_32 }, [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 }, [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 }, }; @@ -218,13 +249,13 @@ static int intc_set_sense(unsigned int irq, unsigned int type) return -EINVAL; } -static unsigned int __init intc_find_mask_handler(unsigned int width) +static unsigned int __init intc_find_dual_handler(unsigned int width) { switch (width) { case 8: - return REG_FN_MASK_8; + return REG_FN_DUAL_8; case 32: - return REG_FN_MASK_32; + return REG_FN_DUAL_32; } BUG(); @@ -244,6 +275,19 @@ static unsigned int __init intc_find_prio_handler(unsigned int width) return REG_FN_ERROR; } +static unsigned int __init intc_find_ena_handler(unsigned int width) +{ + switch (width) { + case 16: + return REG_FN_ENA_16; + case 32: + return REG_FN_ENA_32; + } + + BUG(); + return REG_FN_ERROR; +} + static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) { struct intc_group *g = desc->groups; @@ -301,7 +345,14 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, if (mr->enum_ids[j] != enum_id) continue; - fn = intc_find_mask_handler(mr->reg_width); + switch (mr->clr_reg) { + case 1: /* 1 = enabled interrupt - "enable" register */ + fn = intc_find_ena_handler(mr->reg_width); + break; + default: + fn = intc_find_dual_handler(mr->reg_width); + } + if (fn == REG_FN_ERROR) return 0; |