|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
|
|
|
*
|
|
|
- * Copyright (C) 2007 Magnus Damm
|
|
|
+ * Copyright (C) 2007, 2008 Magnus Damm
|
|
|
*
|
|
|
* Based on intc2.c and ipr.c
|
|
|
*
|
|
@@ -62,6 +62,9 @@ struct intc_desc_int {
|
|
|
#endif
|
|
|
|
|
|
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+static unsigned long ack_handle[NR_IRQS];
|
|
|
+#endif
|
|
|
|
|
|
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
|
|
|
{
|
|
@@ -219,6 +222,25 @@ static void intc_disable(unsigned int irq)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+static void intc_mask_ack(unsigned int irq)
|
|
|
+{
|
|
|
+ struct intc_desc_int *d = get_intc_desc(irq);
|
|
|
+ unsigned long handle = ack_handle[irq];
|
|
|
+ unsigned long addr;
|
|
|
+
|
|
|
+ intc_disable(irq);
|
|
|
+
|
|
|
+ /* read register and write zero only to the assocaited bit */
|
|
|
+
|
|
|
+ if (handle) {
|
|
|
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
|
|
|
+ ctrl_inb(addr);
|
|
|
+ ctrl_outb(0x3f ^ set_field(0, 1, handle), addr);
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
|
|
|
unsigned int nr_hp,
|
|
|
unsigned int irq)
|
|
@@ -430,6 +452,40 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+static unsigned int __init intc_ack_data(struct intc_desc *desc,
|
|
|
+ struct intc_desc_int *d,
|
|
|
+ intc_enum enum_id)
|
|
|
+{
|
|
|
+ struct intc_mask_reg *mr = desc->ack_regs;
|
|
|
+ unsigned int i, j, fn, mode;
|
|
|
+ unsigned long reg_e, reg_d;
|
|
|
+
|
|
|
+ for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
|
|
|
+ mr = desc->ack_regs + i;
|
|
|
+
|
|
|
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
|
|
|
+ if (mr->enum_ids[j] != enum_id)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ fn = REG_FN_MODIFY_BASE;
|
|
|
+ mode = MODE_ENABLE_REG;
|
|
|
+ reg_e = mr->set_reg;
|
|
|
+ reg_d = mr->set_reg;
|
|
|
+
|
|
|
+ fn += (mr->reg_width >> 3) - 1;
|
|
|
+ return _INTC_MK(fn, mode,
|
|
|
+ intc_get_reg(d, reg_e),
|
|
|
+ intc_get_reg(d, reg_d),
|
|
|
+ 1,
|
|
|
+ (mr->reg_width - 1) - j);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static unsigned int __init intc_sense_data(struct intc_desc *desc,
|
|
|
struct intc_desc_int *d,
|
|
|
intc_enum enum_id)
|
|
@@ -530,6 +586,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
|
|
|
|
|
|
/* irq should be disabled by default */
|
|
|
d->chip.mask(irq);
|
|
|
+
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+ if (desc->ack_regs)
|
|
|
+ ack_handle[irq] = intc_ack_data(desc, d, enum_id);
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
static unsigned int __init save_reg(struct intc_desc_int *d,
|
|
@@ -560,6 +621,9 @@ void __init register_intc_controller(struct intc_desc *desc)
|
|
|
d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
|
|
|
d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
|
|
|
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+ d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
|
|
|
+#endif
|
|
|
d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
|
|
|
#ifdef CONFIG_SMP
|
|
|
d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
|
|
@@ -592,14 +656,23 @@ void __init register_intc_controller(struct intc_desc *desc)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
|
|
|
-
|
|
|
d->chip.name = desc->name;
|
|
|
d->chip.mask = intc_disable;
|
|
|
d->chip.unmask = intc_enable;
|
|
|
d->chip.mask_ack = intc_disable;
|
|
|
d->chip.set_type = intc_set_sense;
|
|
|
|
|
|
+#ifdef CONFIG_CPU_SH3
|
|
|
+ if (desc->ack_regs) {
|
|
|
+ for (i = 0; i < desc->nr_ack_regs; i++)
|
|
|
+ k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
|
|
|
+
|
|
|
+ d->chip.mask_ack = intc_mask_ack;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
|
|
|
+
|
|
|
for (i = 0; i < desc->nr_vectors; i++) {
|
|
|
struct intc_vect *vect = desc->vectors + i;
|
|
|
|