Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / arch / m68knommu / platform / coldfire / intc-2.c
1 /*
2  * intc-2.c
3  *
4  * General interrupt controller code for the many ColdFire cores that use
5  * interrupt controllers with 63 interrupt sources, organized as 56 fully-
6  * programmable + 7 fixed-level interrupt sources. This includes the 523x
7  * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
8  * controllers, and the 547x and 548x families which have only one of them.
9  *
10  * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
11  *
12  * This file is subject to the terms and conditions of the GNU General Public
13  * License.  See the file COPYING in the main directory of this archive
14  * for more details.
15  */
16
17 #include <linux/types.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/io.h>
23 #include <asm/coldfire.h>
24 #include <asm/mcfsim.h>
25 #include <asm/traps.h>
26
27 /*
28  * Bit definitions for the ICR family of registers.
29  */
30 #define MCFSIM_ICR_LEVEL(l)     ((l)<<3)        /* Level l intr */
31 #define MCFSIM_ICR_PRI(p)       (p)             /* Priority p intr */
32
33 /*
34  *      Each vector needs a unique priority and level associated with it.
35  *      We don't really care so much what they are, we don't rely on the
36  *      traditional priority interrupt scheme of the m68k/ColdFire.
37  */
38 static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
39
40 #ifdef MCFICM_INTC1
41 #define NR_VECS 128
42 #else
43 #define NR_VECS 64
44 #endif
45
46 static void intc_irq_mask(unsigned int irq)
47 {
48         if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
49                 unsigned long imraddr;
50                 u32 val, imrbit;
51
52                 irq -= MCFINT_VECBASE;
53                 imraddr = MCF_IPSBAR;
54 #ifdef MCFICM_INTC1
55                 imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
56 #else
57                 imraddr += MCFICM_INTC0;
58 #endif
59                 imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
60                 imrbit = 0x1 << (irq & 0x1f);
61
62                 val = __raw_readl(imraddr);
63                 __raw_writel(val | imrbit, imraddr);
64         }
65 }
66
67 static void intc_irq_unmask(unsigned int irq)
68 {
69         if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
70                 unsigned long intaddr, imraddr, icraddr;
71                 u32 val, imrbit;
72
73                 irq -= MCFINT_VECBASE;
74                 intaddr = MCF_IPSBAR;
75 #ifdef MCFICM_INTC1
76                 intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
77 #else
78                 intaddr += MCFICM_INTC0;
79 #endif
80                 imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
81                 icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
82                 imrbit = 0x1 << (irq & 0x1f);
83
84                 /* Don't set the "maskall" bit! */
85                 if ((irq & 0x20) == 0)
86                         imrbit |= 0x1;
87
88                 if (__raw_readb(icraddr) == 0)
89                         __raw_writeb(intc_intpri--, icraddr);
90
91                 val = __raw_readl(imraddr);
92                 __raw_writel(val & ~imrbit, imraddr);
93         }
94 }
95
96 static int intc_irq_set_type(unsigned int irq, unsigned int type)
97 {
98         return 0;
99 }
100
101 static struct irq_chip intc_irq_chip = {
102         .name           = "CF-INTC",
103         .mask           = intc_irq_mask,
104         .unmask         = intc_irq_unmask,
105         .set_type       = intc_irq_set_type,
106 };
107
108 void __init init_IRQ(void)
109 {
110         int irq;
111
112         init_vectors();
113
114         /* Mask all interrupt sources */
115         __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
116 #ifdef MCFICM_INTC1
117         __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
118 #endif
119
120         for (irq = 0; (irq < NR_IRQS); irq++) {
121                 set_irq_chip(irq, &intc_irq_chip);
122                 set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
123                 set_irq_handler(irq, handle_level_irq);
124         }
125 }
126