uclinux-dev  

[uClinux-dev] [RFC 08/11] m68knommu: use generic IRQ with a irq-chip

Sebastian Siewior
Tue, 08 Apr 2008 10:50:27 -0700

This patch implements a basic irq_chip which supports mask / unmask
of interrupt sources. The plan is move more and more drivers to this
approach and setting the IRQ source by them self. 
This is only enabled M523x. Other platforms work as usual.

Signed-off-by: Sebastian Siewior <[EMAIL PROTECTED]> 
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -119,6 +119,7 @@ config M520x
 config M523x
        bool "MCF523x"
        select GENERIC_CLOCKEVENTS
+       select GENERIC_HARDIRQS_NO__DO_IRQ
        help
          Freescale Coldfire 5230/1/2/4/5 processor support
 
@@ -674,6 +675,9 @@ config ROMKERNEL
 
 endchoice
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       bool "Force generic IRQ implementation"
+
 source "kernel/time/Kconfig"
 if COLDFIRE
 source "kernel/Kconfig.preempt"
--- a/arch/m68knommu/kernel/irq.c
+++ b/arch/m68knommu/kernel/irq.c
@@ -23,7 +23,7 @@ asmlinkage void do_IRQ(int irq, struct p
        struct pt_regs *oldregs = set_irq_regs(regs);
 
        irq_enter();
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
 
        set_irq_regs(oldregs);
@@ -34,12 +34,16 @@ void ack_bad_irq(unsigned int irq)
        printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
 }
 
+#ifndef CONFIG_M523x
 static struct irq_chip m_irq_chip = {
        .name           = "M68K-INTC",
        .enable         = enable_vector,
        .disable        = disable_vector,
        .ack            = ack_vector,
 };
+#else
+void coldfire_init_irq_chip(void);
+#endif
 
 void __init init_IRQ(void)
 {
@@ -47,12 +51,16 @@ void __init init_IRQ(void)
 
        init_vectors();
 
+#ifndef CONFIG_M523x
        for (irq = 0; (irq < NR_IRQS); irq++) {
                irq_desc[irq].status = IRQ_DISABLED;
                irq_desc[irq].action = NULL;
                irq_desc[irq].depth = 1;
                irq_desc[irq].chip = &m_irq_chip;
        }
+#else
+       coldfire_init_irq_chip();
+#endif
 }
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -79,4 +87,3 @@ int show_interrupts(struct seq_file *p, 
 
        return 0;
 }
-
--- a/arch/m68knommu/platform/coldfire/Makefile
+++ b/arch/m68knommu/platform/coldfire/Makefile
@@ -20,7 +20,7 @@ obj-$(CONFIG_COLDFIRE)        += dma.o entry.o 
 obj-$(CONFIG_M5206)    += timers.o
 obj-$(CONFIG_M5206e)   += timers.o
 obj-$(CONFIG_M520x)    += pit.o
-obj-$(CONFIG_M523x)    += pit.o dma_timer.o
+obj-$(CONFIG_M523x)    += pit.o dma_timer.o irq_chip.o
 obj-$(CONFIG_M5249)    += timers.o
 obj-$(CONFIG_M527x)    += pit.o
 obj-$(CONFIG_M5272)    += timers.o
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/irq_chip.c
@@ -0,0 +1,110 @@
+/*
+ * IRQ-Chip implementation for Coldfire
+ *
+ * Author: Sebastian Siewior <[EMAIL PROTECTED]>
+ */
+
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void *coldfire_irqnum_to_mem(unsigned int irq)
+{
+       u32 imrp;
+
+       imrp = MCF_IPSBAR;
+#if defined(MCFINT_INTC1_VECBASE)
+       if (irq > MCFINT_INTC1_VECBASE) {
+               imrp += MCFICM_INTC1;
+               irq -= MCFINT_PER_INTC;
+       } else
+#endif
+               imrp += MCFICM_INTC0;
+
+       irq -= MCFINT_VECBASE;
+
+       if (irq > 32)
+               imrp += MCFINTC_IMRH;
+       else
+               imrp += MCFINTC_IMRL;
+
+       return (void *)imrp;
+}
+
+static unsigned int coldfire_irqnum_to_bit(unsigned int irq)
+{
+       irq -= MCFINT_VECBASE;
+
+       if (irq > 32)
+               irq -= 32;
+
+       return irq;
+}
+
+static void coldfire_mask(unsigned int irq)
+{
+       volatile unsigned long *imrp;
+       u32 mask;
+       u32 irq_bit;
+
+       imrp = coldfire_irqnum_to_mem(irq);
+       irq_bit = coldfire_irqnum_to_bit(irq);
+
+       mask = 1 << irq_bit;
+       *imrp |= mask;
+}
+
+static void coldfire_unmask(unsigned int irq)
+{
+       volatile unsigned long *imrp;
+       u32 mask;
+       u32 irq_bit;
+
+       imrp = coldfire_irqnum_to_mem(irq);
+       irq_bit = coldfire_irqnum_to_bit(irq);
+
+       mask = 1 << irq_bit;
+       *imrp &= ~mask;
+}
+
+static void coldfire_nop(unsigned int irq)
+{
+}
+
+static struct irq_chip m_irq_chip = {
+       .name           = "M68K-INTC",
+       .ack            = coldfire_nop,
+       .mask           = coldfire_mask,
+       .unmask         = coldfire_unmask,
+};
+
+void __init coldfire_init_irq_chip(void)
+{
+       volatile u32 *imrp;
+       volatile u8 *icrp;
+       u32 irq;
+       u32 i;
+
+       for (irq = 0; irq < NR_IRQS; irq++)
+               set_irq_chip_and_handler_name(irq, &m_irq_chip,
+                               handle_level_irq, m_irq_chip.name);
+
+       /* setup prios for interrupt sources (first field is reserved) */
+       icrp = (u8 *)MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0;
+       for (i = 1; i <= 63; i++)
+               icrp[i] = i;
+
+       /* remove the disable all flag, disable all interrupt sources */
+       imrp = coldfire_irqnum_to_mem(MCFINT_VECBASE);
+       *imrp = 0xfffffffe;
+
+#if defined(MCFINT_INTC1_VECBASE)
+       icrp = (u8 *)MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_ICR0;
+       for (i = 1; i <= 63; i++)
+               icrp[i] = i;
+
+       imrp = coldfire_irqnum_to_mem(MCFINT_INTC1_VECBASE);
+       *imrp = 0xfffffffe;
+#endif
+}

-- 

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev