Skip to content

Commit

Permalink
sh: intc - add single bitmap register support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Magnus Damm authored and Paul Mundt committed Sep 21, 2007
1 parent 2635e85 commit 51da642
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
73 changes: 62 additions & 11 deletions arch/sh/kernel/cpu/irq/intc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
};
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions include/asm-sh/hw_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct intc_vect {
};

#define INTC_VECT(enum_id, vect) { enum_id, vect }
#define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq))

struct intc_prio {
intc_enum enum_id;
Expand Down

0 comments on commit 51da642

Please sign in to comment.