xref: /openbmc/linux/arch/m68k/coldfire/intc-simr.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
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