1f86b9e03SGreg Ungerer /*
2f86b9e03SGreg Ungerer * intc-simr.c
3f86b9e03SGreg Ungerer *
4f86b9e03SGreg Ungerer * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
5f86b9e03SGreg Ungerer *
6f86b9e03SGreg Ungerer * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
7f86b9e03SGreg Ungerer *
8f86b9e03SGreg Ungerer * This file is subject to the terms and conditions of the GNU General Public
9f86b9e03SGreg Ungerer * License. See the file COPYING in the main directory of this archive
10f86b9e03SGreg Ungerer * for more details.
11f86b9e03SGreg Ungerer */
12f86b9e03SGreg Ungerer
13f86b9e03SGreg Ungerer #include <linux/types.h>
14f86b9e03SGreg Ungerer #include <linux/init.h>
15f86b9e03SGreg Ungerer #include <linux/kernel.h>
16f86b9e03SGreg Ungerer #include <linux/interrupt.h>
17f86b9e03SGreg Ungerer #include <linux/irq.h>
18f86b9e03SGreg Ungerer #include <linux/io.h>
19f86b9e03SGreg Ungerer #include <asm/coldfire.h>
20f86b9e03SGreg Ungerer #include <asm/mcfsim.h>
21f86b9e03SGreg Ungerer #include <asm/traps.h>
22f86b9e03SGreg Ungerer
23f86b9e03SGreg Ungerer /*
24f86b9e03SGreg Ungerer * The EDGE Port interrupts are the fixed 7 external interrupts.
25f86b9e03SGreg Ungerer * They need some special treatment, for example they need to be acked.
26f86b9e03SGreg Ungerer */
27f86b9e03SGreg Ungerer #ifdef CONFIG_M520x
28f86b9e03SGreg Ungerer /*
29f86b9e03SGreg Ungerer * The 520x parts only support a limited range of these external
30f86b9e03SGreg Ungerer * interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67).
31f86b9e03SGreg Ungerer */
32f86b9e03SGreg Ungerer #define EINT0 64 /* Is not actually used, but spot reserved for it */
33f86b9e03SGreg Ungerer #define EINT1 65 /* EDGE Port interrupt 1 */
34f86b9e03SGreg Ungerer #define EINT4 66 /* EDGE Port interrupt 4 */
35f86b9e03SGreg Ungerer #define EINT7 67 /* EDGE Port interrupt 7 */
36f86b9e03SGreg Ungerer
37f86b9e03SGreg Ungerer static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
irq2ebit(unsigned int irq)389d8a9ae2SJoe Perches static inline unsigned int irq2ebit(unsigned int irq)
39f86b9e03SGreg Ungerer {
40f86b9e03SGreg Ungerer return irqebitmap[irq - EINT0];
41f86b9e03SGreg Ungerer }
42f86b9e03SGreg Ungerer
43f86b9e03SGreg Ungerer #else
44f86b9e03SGreg Ungerer
45f86b9e03SGreg Ungerer /*
46f86b9e03SGreg Ungerer * Most of the ColdFire parts with the EDGE Port module just have
47f86b9e03SGreg Ungerer * a strait direct mapping of the 7 external interrupts. Although
48f86b9e03SGreg Ungerer * there is a bit reserved for 0, it is not used.
49f86b9e03SGreg Ungerer */
50f86b9e03SGreg Ungerer #define EINT0 64 /* Is not actually used, but spot reserved for it */
51f86b9e03SGreg Ungerer #define EINT1 65 /* EDGE Port interrupt 1 */
52f86b9e03SGreg Ungerer #define EINT7 71 /* EDGE Port interrupt 7 */
53f86b9e03SGreg Ungerer
irq2ebit(unsigned int irq)549d8a9ae2SJoe Perches static inline unsigned int irq2ebit(unsigned int irq)
55f86b9e03SGreg Ungerer {
56f86b9e03SGreg Ungerer return irq - EINT0;
57f86b9e03SGreg Ungerer }
58f86b9e03SGreg Ungerer
59f86b9e03SGreg Ungerer #endif
60f86b9e03SGreg Ungerer
61f86b9e03SGreg Ungerer /*
62f86b9e03SGreg Ungerer * There maybe one, two or three interrupt control units, each has 64
63f86b9e03SGreg Ungerer * interrupts. If there is no second or third unit then MCFINTC1_* or
64f86b9e03SGreg Ungerer * MCFINTC2_* defines will be 0 (and code for them optimized away).
65f86b9e03SGreg Ungerer */
66f86b9e03SGreg Ungerer
intc_irq_mask(struct irq_data * d)67f86b9e03SGreg Ungerer static void intc_irq_mask(struct irq_data *d)
68f86b9e03SGreg Ungerer {
69f86b9e03SGreg Ungerer unsigned int irq = d->irq - MCFINT_VECBASE;
70f86b9e03SGreg Ungerer
71*6b3788e5SAngelo Dureghello if (MCFINTC2_SIMR && (irq > 127))
72f86b9e03SGreg Ungerer __raw_writeb(irq - 128, MCFINTC2_SIMR);
73*6b3788e5SAngelo Dureghello else if (MCFINTC1_SIMR && (irq > 63))
74f86b9e03SGreg Ungerer __raw_writeb(irq - 64, MCFINTC1_SIMR);
75f86b9e03SGreg Ungerer else
76f86b9e03SGreg Ungerer __raw_writeb(irq, MCFINTC0_SIMR);
77f86b9e03SGreg Ungerer }
78f86b9e03SGreg Ungerer
intc_irq_unmask(struct irq_data * d)79f86b9e03SGreg Ungerer static void intc_irq_unmask(struct irq_data *d)
80f86b9e03SGreg Ungerer {
81f86b9e03SGreg Ungerer unsigned int irq = d->irq - MCFINT_VECBASE;
82f86b9e03SGreg Ungerer
83*6b3788e5SAngelo Dureghello if (MCFINTC2_CIMR && (irq > 127))
84f86b9e03SGreg Ungerer __raw_writeb(irq - 128, MCFINTC2_CIMR);
85*6b3788e5SAngelo Dureghello else if (MCFINTC1_CIMR && (irq > 63))
86f86b9e03SGreg Ungerer __raw_writeb(irq - 64, MCFINTC1_CIMR);
87f86b9e03SGreg Ungerer else
88f86b9e03SGreg Ungerer __raw_writeb(irq, MCFINTC0_CIMR);
89f86b9e03SGreg Ungerer }
90f86b9e03SGreg Ungerer
intc_irq_ack(struct irq_data * d)91f86b9e03SGreg Ungerer static void intc_irq_ack(struct irq_data *d)
92f86b9e03SGreg Ungerer {
93f86b9e03SGreg Ungerer unsigned int ebit = irq2ebit(d->irq);
94f86b9e03SGreg Ungerer
95f86b9e03SGreg Ungerer __raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
96f86b9e03SGreg Ungerer }
97f86b9e03SGreg Ungerer
intc_irq_startup(struct irq_data * d)98f86b9e03SGreg Ungerer static unsigned int intc_irq_startup(struct irq_data *d)
99f86b9e03SGreg Ungerer {
100f86b9e03SGreg Ungerer unsigned int irq = d->irq;
101f86b9e03SGreg Ungerer
102f86b9e03SGreg Ungerer if ((irq >= EINT1) && (irq <= EINT7)) {
103f86b9e03SGreg Ungerer unsigned int ebit = irq2ebit(irq);
104f86b9e03SGreg Ungerer u8 v;
105f86b9e03SGreg Ungerer
106f86b9e03SGreg Ungerer #if defined(MCFEPORT_EPDDR)
107f86b9e03SGreg Ungerer /* Set EPORT line as input */
108f86b9e03SGreg Ungerer v = __raw_readb(MCFEPORT_EPDDR);
109f86b9e03SGreg Ungerer __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
110f86b9e03SGreg Ungerer #endif
111f86b9e03SGreg Ungerer
112f86b9e03SGreg Ungerer /* Set EPORT line as interrupt source */
113f86b9e03SGreg Ungerer v = __raw_readb(MCFEPORT_EPIER);
114f86b9e03SGreg Ungerer __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
115f86b9e03SGreg Ungerer }
116f86b9e03SGreg Ungerer
117f86b9e03SGreg Ungerer irq -= MCFINT_VECBASE;
118*6b3788e5SAngelo Dureghello if (MCFINTC2_ICR0 && (irq > 127))
119f86b9e03SGreg Ungerer __raw_writeb(5, MCFINTC2_ICR0 + irq - 128);
120*6b3788e5SAngelo Dureghello else if (MCFINTC1_ICR0 && (irq > 63))
121f86b9e03SGreg Ungerer __raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
122f86b9e03SGreg Ungerer else
123f86b9e03SGreg Ungerer __raw_writeb(5, MCFINTC0_ICR0 + irq);
124f86b9e03SGreg Ungerer
125f86b9e03SGreg Ungerer intc_irq_unmask(d);
126f86b9e03SGreg Ungerer return 0;
127f86b9e03SGreg Ungerer }
128f86b9e03SGreg Ungerer
intc_irq_set_type(struct irq_data * d,unsigned int type)129f86b9e03SGreg Ungerer static int intc_irq_set_type(struct irq_data *d, unsigned int type)
130f86b9e03SGreg Ungerer {
131f86b9e03SGreg Ungerer unsigned int ebit, irq = d->irq;
132f86b9e03SGreg Ungerer u16 pa, tb;
133f86b9e03SGreg Ungerer
134f86b9e03SGreg Ungerer switch (type) {
135f86b9e03SGreg Ungerer case IRQ_TYPE_EDGE_RISING:
136f86b9e03SGreg Ungerer tb = 0x1;
137f86b9e03SGreg Ungerer break;
138f86b9e03SGreg Ungerer case IRQ_TYPE_EDGE_FALLING:
139f86b9e03SGreg Ungerer tb = 0x2;
140f86b9e03SGreg Ungerer break;
141f86b9e03SGreg Ungerer case IRQ_TYPE_EDGE_BOTH:
142f86b9e03SGreg Ungerer tb = 0x3;
143f86b9e03SGreg Ungerer break;
144f86b9e03SGreg Ungerer default:
145f86b9e03SGreg Ungerer /* Level triggered */
146f86b9e03SGreg Ungerer tb = 0;
147f86b9e03SGreg Ungerer break;
148f86b9e03SGreg Ungerer }
149f86b9e03SGreg Ungerer
150f86b9e03SGreg Ungerer if (tb)
151f86b9e03SGreg Ungerer irq_set_handler(irq, handle_edge_irq);
152f86b9e03SGreg Ungerer
153f86b9e03SGreg Ungerer ebit = irq2ebit(irq) * 2;
154f86b9e03SGreg Ungerer pa = __raw_readw(MCFEPORT_EPPAR);
155f86b9e03SGreg Ungerer pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
156f86b9e03SGreg Ungerer __raw_writew(pa, MCFEPORT_EPPAR);
157f86b9e03SGreg Ungerer
158f86b9e03SGreg Ungerer return 0;
159f86b9e03SGreg Ungerer }
160f86b9e03SGreg Ungerer
161f86b9e03SGreg Ungerer static struct irq_chip intc_irq_chip = {
162f86b9e03SGreg Ungerer .name = "CF-INTC",
163f86b9e03SGreg Ungerer .irq_startup = intc_irq_startup,
164f86b9e03SGreg Ungerer .irq_mask = intc_irq_mask,
165f86b9e03SGreg Ungerer .irq_unmask = intc_irq_unmask,
166f86b9e03SGreg Ungerer };
167f86b9e03SGreg Ungerer
168f86b9e03SGreg Ungerer static struct irq_chip intc_irq_chip_edge_port = {
169f86b9e03SGreg Ungerer .name = "CF-INTC-EP",
170f86b9e03SGreg Ungerer .irq_startup = intc_irq_startup,
171f86b9e03SGreg Ungerer .irq_mask = intc_irq_mask,
172f86b9e03SGreg Ungerer .irq_unmask = intc_irq_unmask,
173f86b9e03SGreg Ungerer .irq_ack = intc_irq_ack,
174f86b9e03SGreg Ungerer .irq_set_type = intc_irq_set_type,
175f86b9e03SGreg Ungerer };
176f86b9e03SGreg Ungerer
init_IRQ(void)177f86b9e03SGreg Ungerer void __init init_IRQ(void)
178f86b9e03SGreg Ungerer {
179f86b9e03SGreg Ungerer int irq, eirq;
180f86b9e03SGreg Ungerer
181f86b9e03SGreg Ungerer /* Mask all interrupt sources */
182f86b9e03SGreg Ungerer __raw_writeb(0xff, MCFINTC0_SIMR);
183f86b9e03SGreg Ungerer if (MCFINTC1_SIMR)
184f86b9e03SGreg Ungerer __raw_writeb(0xff, MCFINTC1_SIMR);
185f86b9e03SGreg Ungerer if (MCFINTC2_SIMR)
186f86b9e03SGreg Ungerer __raw_writeb(0xff, MCFINTC2_SIMR);
187f86b9e03SGreg Ungerer
188f86b9e03SGreg Ungerer eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0) +
189f86b9e03SGreg Ungerer (MCFINTC2_ICR0 ? 64 : 0);
190f86b9e03SGreg Ungerer for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
191f86b9e03SGreg Ungerer if ((irq >= EINT1) && (irq <= EINT7))
192f86b9e03SGreg Ungerer irq_set_chip(irq, &intc_irq_chip_edge_port);
193f86b9e03SGreg Ungerer else
194f86b9e03SGreg Ungerer irq_set_chip(irq, &intc_irq_chip);
195f86b9e03SGreg Ungerer irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
196f86b9e03SGreg Ungerer irq_set_handler(irq, handle_level_irq);
197f86b9e03SGreg Ungerer }
198f86b9e03SGreg Ungerer }
199f86b9e03SGreg Ungerer
200