Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/platform/coldfire/intc-simr.c
10819 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 unsigned int inline 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 unsigned int inline irq2ebit(unsigned int irq)
55
{
56
return irq - EINT0;
57
}
58
59
#endif
60
61
/*
62
* There maybe one or two interrupt control units, each has 64
63
* interrupts. If there is no second unit then MCFINTC1_* defines
64
* 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 (MCFINTC1_SIMR && (irq > 64))
72
__raw_writeb(irq - 64, MCFINTC1_SIMR);
73
else
74
__raw_writeb(irq, MCFINTC0_SIMR);
75
}
76
77
static void intc_irq_unmask(struct irq_data *d)
78
{
79
unsigned int irq = d->irq - MCFINT_VECBASE;
80
81
if (MCFINTC1_CIMR && (irq > 64))
82
__raw_writeb(irq - 64, MCFINTC1_CIMR);
83
else
84
__raw_writeb(irq, MCFINTC0_CIMR);
85
}
86
87
static void intc_irq_ack(struct irq_data *d)
88
{
89
unsigned int ebit = irq2ebit(d->irq);
90
91
__raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
92
}
93
94
static unsigned int intc_irq_startup(struct irq_data *d)
95
{
96
unsigned int irq = d->irq;
97
98
if ((irq >= EINT1) && (irq <= EINT7)) {
99
unsigned int ebit = irq2ebit(irq);
100
u8 v;
101
102
/* Set EPORT line as input */
103
v = __raw_readb(MCFEPORT_EPDDR);
104
__raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
105
106
/* Set EPORT line as interrupt source */
107
v = __raw_readb(MCFEPORT_EPIER);
108
__raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
109
}
110
111
irq -= MCFINT_VECBASE;
112
if (MCFINTC1_ICR0 && (irq > 64))
113
__raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
114
else
115
__raw_writeb(5, MCFINTC0_ICR0 + irq);
116
117
118
intc_irq_unmask(d);
119
return 0;
120
}
121
122
static int intc_irq_set_type(struct irq_data *d, unsigned int type)
123
{
124
unsigned int ebit, irq = d->irq;
125
u16 pa, tb;
126
127
switch (type) {
128
case IRQ_TYPE_EDGE_RISING:
129
tb = 0x1;
130
break;
131
case IRQ_TYPE_EDGE_FALLING:
132
tb = 0x2;
133
break;
134
case IRQ_TYPE_EDGE_BOTH:
135
tb = 0x3;
136
break;
137
default:
138
/* Level triggered */
139
tb = 0;
140
break;
141
}
142
143
if (tb)
144
irq_set_handler(irq, handle_edge_irq);
145
146
ebit = irq2ebit(irq) * 2;
147
pa = __raw_readw(MCFEPORT_EPPAR);
148
pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
149
__raw_writew(pa, MCFEPORT_EPPAR);
150
151
return 0;
152
}
153
154
static struct irq_chip intc_irq_chip = {
155
.name = "CF-INTC",
156
.irq_startup = intc_irq_startup,
157
.irq_mask = intc_irq_mask,
158
.irq_unmask = intc_irq_unmask,
159
};
160
161
static struct irq_chip intc_irq_chip_edge_port = {
162
.name = "CF-INTC-EP",
163
.irq_startup = intc_irq_startup,
164
.irq_mask = intc_irq_mask,
165
.irq_unmask = intc_irq_unmask,
166
.irq_ack = intc_irq_ack,
167
.irq_set_type = intc_irq_set_type,
168
};
169
170
void __init init_IRQ(void)
171
{
172
int irq, eirq;
173
174
init_vectors();
175
176
/* Mask all interrupt sources */
177
__raw_writeb(0xff, MCFINTC0_SIMR);
178
if (MCFINTC1_SIMR)
179
__raw_writeb(0xff, MCFINTC1_SIMR);
180
181
eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0);
182
for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
183
if ((irq >= EINT1) && (irq <= EINT7))
184
irq_set_chip(irq, &intc_irq_chip_edge_port);
185
else
186
irq_set_chip(irq, &intc_irq_chip);
187
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
188
irq_set_handler(irq, handle_level_irq);
189
}
190
}
191
192
193