Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/qoriq/qoriq_gpio_pic.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2021 Alstom Group.
5
* Copyright (c) 2021 Semihalf.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/conf.h>
31
#include <sys/bus.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
#include <sys/mutex.h>
35
#include <sys/proc.h>
36
#include <sys/rman.h>
37
#include <sys/stdarg.h>
38
#include <sys/gpio.h>
39
40
#include <machine/bus.h>
41
#include <machine/resource.h>
42
43
#include <dev/gpio/gpiobusvar.h>
44
#include <dev/gpio/qoriq_gpio.h>
45
#include <dev/ofw/ofw_bus.h>
46
#include <dev/ofw/ofw_bus_subr.h>
47
48
#include <dt-bindings/interrupt-controller/irq.h>
49
50
#include "gpio_if.h"
51
#include "pic_if.h"
52
53
struct qoriq_gpio_pic_irqsrc {
54
struct intr_irqsrc isrc;
55
int pin;
56
};
57
58
struct qoriq_gpio_pic_softc {
59
struct qoriq_gpio_softc base;
60
61
struct resource *res_irq;
62
void *irq_cookie;
63
struct qoriq_gpio_pic_irqsrc isrcs[MAXPIN + 1];
64
struct intr_map_data_gpio gdata;
65
};
66
67
#define RD4(sc, off) bus_read_4((sc)->base.sc_mem, (off))
68
#define WR4(sc, off, data) bus_write_4((sc)->base.sc_mem, (off), (data))
69
70
static device_probe_t qoriq_gpio_pic_probe;
71
static device_attach_t qoriq_gpio_pic_attach;
72
static device_detach_t qoriq_gpio_pic_detach;
73
74
static void
75
qoriq_gpio_pic_set_intr(struct qoriq_gpio_pic_softc *sc, int pin, bool enable)
76
{
77
uint32_t reg;
78
79
reg = RD4(sc, GPIO_GPIMR);
80
if (enable)
81
reg |= BIT(31 - pin);
82
else
83
reg &= ~BIT(31 - pin);
84
WR4(sc, GPIO_GPIMR, reg);
85
}
86
87
static void
88
qoriq_gpio_pic_ack_intr(struct qoriq_gpio_pic_softc *sc, int pin)
89
{
90
uint32_t reg;
91
92
reg = BIT(31 - pin);
93
WR4(sc, GPIO_GPIER, reg);
94
}
95
96
static int
97
qoriq_gpio_pic_intr(void *arg)
98
{
99
struct qoriq_gpio_pic_softc *sc;
100
struct trapframe *tf;
101
uint32_t status;
102
int pin;
103
104
sc = (struct qoriq_gpio_pic_softc *)arg;
105
tf = curthread->td_intr_frame;
106
107
status = RD4(sc, GPIO_GPIER);
108
status &= RD4(sc, GPIO_GPIMR);
109
while (status != 0) {
110
pin = ffs(status) - 1;
111
status &= ~BIT(pin);
112
pin = 31 - pin;
113
114
if (intr_isrc_dispatch(&sc->isrcs[pin].isrc, tf) != 0) {
115
GPIO_LOCK(&sc->base);
116
qoriq_gpio_pic_set_intr(sc, pin, false);
117
qoriq_gpio_pic_ack_intr(sc, pin);
118
GPIO_UNLOCK(&sc->base);
119
device_printf(sc->base.dev,
120
"Masking spurious pin interrupt %d\n",
121
pin);
122
}
123
}
124
125
return (FILTER_HANDLED);
126
}
127
128
static void
129
qoriq_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
130
{
131
struct qoriq_gpio_pic_softc *sc;
132
struct qoriq_gpio_pic_irqsrc *qisrc;
133
134
sc = device_get_softc(dev);
135
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
136
137
GPIO_LOCK(&sc->base);
138
qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
139
GPIO_UNLOCK(&sc->base);
140
}
141
142
static void
143
qoriq_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
144
{
145
struct qoriq_gpio_pic_softc *sc;
146
struct qoriq_gpio_pic_irqsrc *qisrc;
147
148
sc = device_get_softc(dev);
149
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
150
151
GPIO_LOCK(&sc->base);
152
qoriq_gpio_pic_set_intr(sc, qisrc->pin, true);
153
GPIO_UNLOCK(&sc->base);
154
}
155
156
static struct intr_map_data_gpio*
157
qoriq_gpio_pic_convert_map_data(struct qoriq_gpio_pic_softc *sc, struct intr_map_data *data)
158
{
159
struct intr_map_data_gpio *gdata;
160
struct intr_map_data_fdt *daf;
161
162
switch (data->type) {
163
case INTR_MAP_DATA_GPIO:
164
gdata = (struct intr_map_data_gpio *)data;
165
break;
166
case INTR_MAP_DATA_FDT:
167
daf = (struct intr_map_data_fdt *)data;
168
if (daf->ncells != 2)
169
return (NULL);
170
171
gdata = &sc->gdata;
172
gdata->gpio_pin_num = daf->cells[0];
173
switch (daf->cells[1]) {
174
case IRQ_TYPE_LEVEL_LOW:
175
gdata->gpio_intr_mode = GPIO_INTR_LEVEL_LOW;
176
break;
177
case IRQ_TYPE_LEVEL_HIGH:
178
gdata->gpio_intr_mode = GPIO_INTR_LEVEL_HIGH;
179
break;
180
case IRQ_TYPE_EDGE_RISING:
181
gdata->gpio_intr_mode = GPIO_INTR_EDGE_RISING;
182
break;
183
case IRQ_TYPE_EDGE_FALLING:
184
gdata->gpio_intr_mode = GPIO_INTR_EDGE_FALLING;
185
break;
186
case IRQ_TYPE_EDGE_BOTH:
187
gdata->gpio_intr_mode = GPIO_INTR_EDGE_BOTH;
188
break;
189
default:
190
return (NULL);
191
}
192
break;
193
default:
194
return (NULL);
195
}
196
197
return (gdata);
198
}
199
200
201
static int
202
qoriq_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
203
struct intr_irqsrc **isrcp)
204
{
205
struct qoriq_gpio_pic_softc *sc;
206
struct intr_map_data_gpio *gdata;
207
int pin;
208
209
sc = device_get_softc(dev);
210
211
gdata = qoriq_gpio_pic_convert_map_data(sc, data);
212
if (gdata == NULL)
213
return (EINVAL);
214
215
pin = gdata->gpio_pin_num;
216
if (pin > MAXPIN)
217
return (EINVAL);
218
219
*isrcp = &sc->isrcs[pin].isrc;
220
return (0);
221
}
222
223
static int
224
qoriq_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
225
struct resource *res, struct intr_map_data *data)
226
{
227
struct qoriq_gpio_pic_softc *sc;
228
struct intr_map_data_gpio *gdata;
229
struct qoriq_gpio_pic_irqsrc *qisrc;
230
bool falling;
231
uint32_t reg;
232
233
sc = device_get_softc(dev);
234
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
235
236
gdata = qoriq_gpio_pic_convert_map_data(sc, data);
237
if (gdata == NULL)
238
return (EINVAL);
239
240
if (gdata->gpio_intr_mode & GPIO_INTR_EDGE_BOTH)
241
falling = false;
242
else if (gdata->gpio_intr_mode & GPIO_INTR_EDGE_FALLING)
243
falling = true;
244
else
245
return (EOPNOTSUPP);
246
247
GPIO_LOCK(&sc->base);
248
reg = RD4(sc, GPIO_GPICR);
249
if (falling)
250
reg |= BIT(31 - qisrc->pin);
251
else
252
reg &= ~BIT(31 - qisrc->pin);
253
WR4(sc, GPIO_GPICR, reg);
254
GPIO_UNLOCK(&sc->base);
255
256
return (0);
257
}
258
259
static int
260
qoriq_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
261
struct resource *res, struct intr_map_data *data)
262
{
263
struct qoriq_gpio_pic_softc *sc;
264
struct qoriq_gpio_pic_irqsrc *qisrc;
265
266
sc = device_get_softc(dev);
267
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
268
269
if (isrc->isrc_handlers > 0)
270
return (0);
271
272
GPIO_LOCK(&sc->base);
273
qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
274
GPIO_UNLOCK(&sc->base);
275
return (0);
276
}
277
278
static void
279
qoriq_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
280
{
281
struct qoriq_gpio_pic_softc *sc;
282
struct qoriq_gpio_pic_irqsrc *qisrc;
283
284
sc = device_get_softc(dev);
285
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
286
287
GPIO_LOCK(&sc->base);
288
qoriq_gpio_pic_ack_intr(sc, qisrc->pin);
289
GPIO_UNLOCK(&sc->base);
290
}
291
292
293
static void
294
qoriq_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
295
{
296
struct qoriq_gpio_pic_softc *sc;
297
struct qoriq_gpio_pic_irqsrc *qisrc;
298
299
sc = device_get_softc(dev);
300
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
301
302
GPIO_LOCK(&sc->base);
303
qoriq_gpio_pic_ack_intr(sc, qisrc->pin);
304
qoriq_gpio_pic_set_intr(sc, qisrc->pin, true);
305
GPIO_UNLOCK(&sc->base);
306
}
307
308
static void
309
qoriq_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
310
{
311
struct qoriq_gpio_pic_softc *sc;
312
struct qoriq_gpio_pic_irqsrc *qisrc;
313
314
sc = device_get_softc(dev);
315
qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
316
317
GPIO_LOCK(&sc->base);
318
qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
319
GPIO_UNLOCK(&sc->base);
320
321
}
322
static int
323
qoriq_gpio_pic_probe(device_t dev)
324
{
325
if (!ofw_bus_status_okay(dev))
326
return (ENXIO);
327
328
if (!ofw_bus_is_compatible(dev, "fsl,qoriq-gpio"))
329
return (ENXIO);
330
331
device_set_desc(dev, "Freescale QorIQ GPIO PIC driver");
332
333
return (BUS_PROBE_DEFAULT);
334
}
335
336
static int
337
qoriq_gpio_pic_attach(device_t dev)
338
{
339
struct qoriq_gpio_pic_softc *sc;
340
int error, rid, i;
341
const char *name;
342
intptr_t xref;
343
344
sc = device_get_softc(dev);
345
346
error = qoriq_gpio_attach(dev);
347
if (error != 0)
348
return (error);
349
350
rid = 0;
351
sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
352
RF_ACTIVE | RF_SHAREABLE);
353
if (sc->res_irq == NULL) {
354
device_printf(dev, "Can't allocate interrupt resource.\n");
355
error = ENOMEM;
356
goto fail;
357
}
358
359
error = bus_setup_intr(dev, sc->res_irq, INTR_TYPE_MISC | INTR_MPSAFE,
360
qoriq_gpio_pic_intr, NULL, sc, &sc->irq_cookie);
361
if (error != 0) {
362
device_printf(dev, "Failed to setup interrupt.\n");
363
goto fail;
364
}
365
366
name = device_get_nameunit(dev);
367
for (i = 0; i <= MAXPIN; i++) {
368
sc->isrcs[i].pin = i;
369
error = intr_isrc_register(&sc->isrcs[i].isrc,
370
dev, 0, "%s,%u", name, i);
371
if (error != 0)
372
goto fail;
373
}
374
375
xref = OF_xref_from_node(ofw_bus_get_node(dev));
376
if (intr_pic_register(dev, xref) == NULL) {
377
error = ENXIO;
378
goto fail;
379
}
380
381
/* ACK and mask all interrupts. */
382
WR4(sc, GPIO_GPIER, 0xffffffff);
383
WR4(sc, GPIO_GPIMR, 0);
384
385
return (0);
386
fail:
387
qoriq_gpio_pic_detach(dev);
388
return (error);
389
}
390
391
static int
392
qoriq_gpio_pic_detach(device_t dev)
393
{
394
struct qoriq_gpio_pic_softc *sc;
395
396
sc = device_get_softc(dev);
397
398
if (sc->irq_cookie != NULL)
399
bus_teardown_intr(dev, sc->res_irq, sc->irq_cookie);
400
401
if (sc->res_irq != NULL)
402
bus_release_resource(dev, SYS_RES_IRQ,
403
rman_get_rid(sc->res_irq), sc->res_irq);
404
405
return (qoriq_gpio_detach(dev));
406
}
407
408
409
static device_method_t qoriq_gpio_pic_methods[] = {
410
DEVMETHOD(device_probe, qoriq_gpio_pic_probe),
411
DEVMETHOD(device_attach, qoriq_gpio_pic_attach),
412
DEVMETHOD(device_detach, qoriq_gpio_pic_detach),
413
414
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
415
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
416
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
417
418
DEVMETHOD(pic_disable_intr, qoriq_gpio_pic_disable_intr),
419
DEVMETHOD(pic_enable_intr, qoriq_gpio_pic_enable_intr),
420
DEVMETHOD(pic_map_intr, qoriq_gpio_pic_map_intr),
421
DEVMETHOD(pic_setup_intr, qoriq_gpio_pic_setup_intr),
422
DEVMETHOD(pic_teardown_intr, qoriq_gpio_pic_teardown_intr),
423
DEVMETHOD(pic_post_filter, qoriq_gpio_pic_post_filter),
424
DEVMETHOD(pic_post_ithread, qoriq_gpio_pic_post_ithread),
425
DEVMETHOD(pic_pre_ithread, qoriq_gpio_pic_pre_ithread),
426
427
DEVMETHOD_END
428
};
429
430
DEFINE_CLASS_1(gpio, qoriq_gpio_pic_driver, qoriq_gpio_pic_methods,
431
sizeof(struct qoriq_gpio_pic_softc), qoriq_gpio_driver);
432
EARLY_DRIVER_MODULE(qoriq_gpio_pic, simplebus, qoriq_gpio_pic_driver, NULL, NULL,
433
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
434
435