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