Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/mpc85xx/atpic.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009 Marcel Moolenaar
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/bus.h>
31
#include <sys/cpuset.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
#include <sys/rman.h>
35
36
#include <machine/bus.h>
37
#include <machine/intr_machdep.h>
38
#include <machine/pio.h>
39
40
#include <powerpc/mpc85xx/mpc85xx.h>
41
42
#include <dev/ic/i8259.h>
43
44
#include <isa/isareg.h>
45
#include <isa/isavar.h>
46
47
#include "pic_if.h"
48
49
#define ATPIC_MASTER 0
50
#define ATPIC_SLAVE 1
51
52
struct atpic_softc {
53
device_t sc_dev;
54
55
/* I/O port resources for master & slave. */
56
struct resource *sc_res[2];
57
int sc_rid[2];
58
59
/* Our "routing" interrupt */
60
struct resource *sc_ires;
61
void *sc_icookie;
62
int sc_irid;
63
64
int sc_vector[16];
65
uint8_t sc_mask[2];
66
};
67
68
static int atpic_isa_attach(device_t);
69
static void atpic_isa_identify(driver_t *, device_t);
70
static int atpic_isa_probe(device_t);
71
72
static void atpic_config(device_t, u_int, enum intr_trigger,
73
enum intr_polarity);
74
static void atpic_dispatch(device_t, struct trapframe *);
75
static void atpic_enable(device_t, u_int, u_int);
76
static void atpic_eoi(device_t, u_int);
77
static void atpic_ipi(device_t, u_int);
78
static void atpic_mask(device_t, u_int);
79
static void atpic_unmask(device_t, u_int);
80
81
static void atpic_ofw_translate_code(device_t, u_int irq, int code,
82
enum intr_trigger *trig, enum intr_polarity *pol);
83
84
static device_method_t atpic_isa_methods[] = {
85
/* Device interface */
86
DEVMETHOD(device_identify, atpic_isa_identify),
87
DEVMETHOD(device_probe, atpic_isa_probe),
88
DEVMETHOD(device_attach, atpic_isa_attach),
89
90
/* PIC interface */
91
DEVMETHOD(pic_config, atpic_config),
92
DEVMETHOD(pic_dispatch, atpic_dispatch),
93
DEVMETHOD(pic_enable, atpic_enable),
94
DEVMETHOD(pic_eoi, atpic_eoi),
95
DEVMETHOD(pic_ipi, atpic_ipi),
96
DEVMETHOD(pic_mask, atpic_mask),
97
DEVMETHOD(pic_unmask, atpic_unmask),
98
99
DEVMETHOD(pic_translate_code, atpic_ofw_translate_code),
100
101
{ 0, 0 },
102
};
103
104
static driver_t atpic_isa_driver = {
105
"atpic",
106
atpic_isa_methods,
107
sizeof(struct atpic_softc)
108
};
109
110
static struct isa_pnp_id atpic_ids[] = {
111
{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
112
{ 0 }
113
};
114
115
DRIVER_MODULE(atpic, isa, atpic_isa_driver, 0, 0);
116
ISA_PNP_INFO(atpic_ids);
117
118
static __inline uint8_t
119
atpic_read(struct atpic_softc *sc, int icu, int ofs)
120
{
121
uint8_t val;
122
123
val = bus_read_1(sc->sc_res[icu], ofs);
124
return (val);
125
}
126
127
static __inline void
128
atpic_write(struct atpic_softc *sc, int icu, int ofs, uint8_t val)
129
{
130
131
bus_write_1(sc->sc_res[icu], ofs, val);
132
bus_barrier(sc->sc_res[icu], ofs, 2 - ofs,
133
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
134
}
135
136
static void
137
atpic_intr(void *arg)
138
{
139
140
atpic_dispatch(arg, NULL);
141
}
142
143
static void
144
atpic_isa_identify(driver_t *drv, device_t parent)
145
{
146
device_t child;
147
148
child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, drv->name, DEVICE_UNIT_ANY);
149
device_set_driver(child, drv);
150
isa_set_logicalid(child, atpic_ids[0].ip_id);
151
isa_set_vendorid(child, atpic_ids[0].ip_id);
152
153
bus_set_resource(child, SYS_RES_IOPORT, ATPIC_MASTER, IO_ICU1, 2);
154
bus_set_resource(child, SYS_RES_IOPORT, ATPIC_SLAVE, IO_ICU2, 2);
155
156
/* ISA interrupts are routed through external interrupt 0. */
157
bus_set_resource(child, SYS_RES_IRQ, 0, 16, 1);
158
}
159
160
static int
161
atpic_isa_probe(device_t dev)
162
{
163
int res;
164
165
res = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
166
if (res > 0)
167
return (res);
168
169
device_set_desc(dev, "PC/AT compatible PIC");
170
return (res);
171
}
172
173
static void
174
atpic_init(struct atpic_softc *sc, int icu)
175
{
176
177
sc->sc_mask[icu] = 0xff - ((icu == ATPIC_MASTER) ? 4 : 0);
178
179
atpic_write(sc, icu, 0, ICW1_RESET | ICW1_IC4);
180
atpic_write(sc, icu, 1, (icu == ATPIC_SLAVE) ? 8 : 0);
181
atpic_write(sc, icu, 1, (icu == ATPIC_SLAVE) ? 2 : 4);
182
atpic_write(sc, icu, 1, ICW4_8086);
183
atpic_write(sc, icu, 1, sc->sc_mask[icu]);
184
atpic_write(sc, icu, 0, OCW3_SEL | OCW3_RR);
185
}
186
187
static int
188
atpic_isa_attach(device_t dev)
189
{
190
struct atpic_softc *sc;
191
int error;
192
193
sc = device_get_softc(dev);
194
sc->sc_dev = dev;
195
196
error = ENXIO;
197
198
sc->sc_rid[ATPIC_MASTER] = 0;
199
sc->sc_res[ATPIC_MASTER] = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
200
&sc->sc_rid[ATPIC_MASTER], RF_ACTIVE);
201
if (sc->sc_res[ATPIC_MASTER] == NULL)
202
goto fail;
203
204
sc->sc_rid[ATPIC_SLAVE] = 1;
205
sc->sc_res[ATPIC_SLAVE] = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
206
&sc->sc_rid[ATPIC_SLAVE], RF_ACTIVE);
207
if (sc->sc_res[ATPIC_SLAVE] == NULL)
208
goto fail;
209
210
sc->sc_irid = 0;
211
sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
212
RF_ACTIVE);
213
if (sc->sc_ires == NULL)
214
goto fail;
215
216
error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_MISC | INTR_MPSAFE,
217
NULL, atpic_intr, dev, &sc->sc_icookie);
218
if (error)
219
goto fail;
220
221
atpic_init(sc, ATPIC_SLAVE);
222
atpic_init(sc, ATPIC_MASTER);
223
224
powerpc_register_pic(dev, 0, 16, 0, TRUE);
225
return (0);
226
227
fail:
228
if (sc->sc_ires != NULL)
229
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
230
sc->sc_ires);
231
if (sc->sc_res[ATPIC_SLAVE] != NULL)
232
bus_release_resource(dev, SYS_RES_IOPORT,
233
sc->sc_rid[ATPIC_SLAVE], sc->sc_res[ATPIC_SLAVE]);
234
if (sc->sc_res[ATPIC_MASTER] != NULL)
235
bus_release_resource(dev, SYS_RES_IOPORT,
236
sc->sc_rid[ATPIC_MASTER], sc->sc_res[ATPIC_MASTER]);
237
return (error);
238
}
239
240
/*
241
* PIC interface.
242
*/
243
244
static void
245
atpic_config(device_t dev, u_int irq, enum intr_trigger trig,
246
enum intr_polarity pol)
247
{
248
}
249
250
static void
251
atpic_dispatch(device_t dev, struct trapframe *tf)
252
{
253
struct atpic_softc *sc;
254
uint8_t irq;
255
256
sc = device_get_softc(dev);
257
atpic_write(sc, ATPIC_MASTER, 0, OCW3_SEL | OCW3_P);
258
irq = atpic_read(sc, ATPIC_MASTER, 0);
259
atpic_write(sc, ATPIC_MASTER, 0, OCW3_SEL | OCW3_RR);
260
if ((irq & 0x80) == 0)
261
return;
262
263
if (irq == 0x82) {
264
atpic_write(sc, ATPIC_SLAVE, 0, OCW3_SEL | OCW3_P);
265
irq = atpic_read(sc, ATPIC_SLAVE, 0) + 8;
266
atpic_write(sc, ATPIC_SLAVE, 0, OCW3_SEL | OCW3_RR);
267
if ((irq & 0x80) == 0)
268
return;
269
}
270
271
powerpc_dispatch_intr(sc->sc_vector[irq & 0x0f], tf);
272
}
273
274
static void
275
atpic_enable(device_t dev, u_int irq, u_int vector)
276
{
277
struct atpic_softc *sc;
278
279
sc = device_get_softc(dev);
280
sc->sc_vector[irq] = vector;
281
atpic_unmask(dev, irq);
282
}
283
284
static void
285
atpic_eoi(device_t dev, u_int irq)
286
{
287
struct atpic_softc *sc;
288
289
sc = device_get_softc(dev);
290
if (irq > 7)
291
atpic_write(sc, ATPIC_SLAVE, 0, OCW2_EOI);
292
atpic_write(sc, ATPIC_MASTER, 0, OCW2_EOI);
293
}
294
295
static void
296
atpic_ipi(device_t dev, u_int cpu)
297
{
298
/* No SMP support. */
299
}
300
301
static void
302
atpic_mask(device_t dev, u_int irq)
303
{
304
struct atpic_softc *sc;
305
306
sc = device_get_softc(dev);
307
if (irq > 7) {
308
sc->sc_mask[ATPIC_SLAVE] |= 1 << (irq - 8);
309
atpic_write(sc, ATPIC_SLAVE, 1, sc->sc_mask[ATPIC_SLAVE]);
310
} else {
311
sc->sc_mask[ATPIC_MASTER] |= 1 << irq;
312
atpic_write(sc, ATPIC_MASTER, 1, sc->sc_mask[ATPIC_MASTER]);
313
}
314
}
315
316
static void
317
atpic_unmask(device_t dev, u_int irq)
318
{
319
struct atpic_softc *sc;
320
321
sc = device_get_softc(dev);
322
if (irq > 7) {
323
sc->sc_mask[ATPIC_SLAVE] &= ~(1 << (irq - 8));
324
atpic_write(sc, ATPIC_SLAVE, 1, sc->sc_mask[ATPIC_SLAVE]);
325
} else {
326
sc->sc_mask[ATPIC_MASTER] &= ~(1 << irq);
327
atpic_write(sc, ATPIC_MASTER, 1, sc->sc_mask[ATPIC_MASTER]);
328
}
329
}
330
331
static void
332
atpic_ofw_translate_code(device_t dev, u_int irq, int code,
333
enum intr_trigger *trig, enum intr_polarity *pol)
334
{
335
switch (code) {
336
case 0:
337
/* Active L level */
338
*trig = INTR_TRIGGER_LEVEL;
339
*pol = INTR_POLARITY_LOW;
340
break;
341
case 1:
342
/* Active H level */
343
*trig = INTR_TRIGGER_LEVEL;
344
*pol = INTR_POLARITY_HIGH;
345
break;
346
case 2:
347
/* H to L edge */
348
*trig = INTR_TRIGGER_EDGE;
349
*pol = INTR_POLARITY_LOW;
350
break;
351
case 3:
352
/* L to H edge */
353
*trig = INTR_TRIGGER_EDGE;
354
*pol = INTR_POLARITY_HIGH;
355
break;
356
default:
357
*trig = INTR_TRIGGER_CONFORM;
358
*pol = INTR_POLARITY_CONFORM;
359
}
360
}
361
362